Skip to main content

antigravity-native-e2e-dev

Spin up a live local Omnigent server + runner and exercise the native Antigravity (agy) TUI harness (antigravity-native) end-to-end — launch the real `agy` CLI via `omnigent antigravity`, drive turns through the web UI, smoke-test, and bug-bash. Load when developing, testing, or debugging the antigravity-native harness (omnigent/inner/antigravity_native_executor.py, omnigent/antigravity_native.py, antigravity_native_bridge.py, antigravity_native_rpc.py, antigravity_native_reader.py, antigravity_native_launch.py) or its agy launch / RPC mirror / tmux delivery / OAuth / MCP-relay behavior. NOT the in-process `antigravity` Gemini SDK harness.

소스 정보

저장소
omnigent-ai/omnigent
최근 소스 활동
2026년 10월 21일 05:01
감지된 SKILL.md 언어
영어
스타
11,106
포크
1,828

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
antigravity-native-e2e-dev
description
Spin up a live local Omnigent server + runner and exercise the native Antigravity (agy) TUI harness (antigravity-native) end-to-end — launch the real `agy` CLI via `omnigent antigravity`, drive turns through the web UI, smoke-test, and bug-bash. Load when developing, testing, or debugging the antigravity-native harness (omnigent/inner/antigravity_native_executor.py, omnigent/antigravity_native.py, antigravity_native_bridge.py, antigravity_native_rpc.py, antigravity_native_reader.py, antigravity_native_launch.py) or its agy launch / RPC mirror / tmux delivery / OAuth / MCP-relay behavior. NOT the in-process `antigravity` Gemini SDK harness.
# Antigravity native harness: end-to-end dev & testing (local server/runner) The `antigravity-native` harness wraps the **real Antigravity `agy` TUI** (the `agy` CLI, installed from `antigravity.google/cli/install.sh`). `omnigent antigravity` ensures a host daemon, the daemon-spawned **runner** launches `agy` in a runner-owned **tmux** terminal, and your TTY attaches to it. This is **not** the in-process `antigravity` Gemini-SDK harness — that one runs `google-antigravity` with separate SDK settings; this one drives the `agy` CLI and mirrors it over **connect-RPC**. This skill is the proven recipe for running it **for real against a live local server + runner** — not just the unit tests. > Like the other native harnesses, the runner imports from your **current > checkout**, so testing here exercises exactly the code you're on. (CWD/venv > selects the code, not `PYTHONPATH`.) ## What actually runs where ``` your TTY ── (attach / pexpect) ──► omnigent antigravity (CLI, local) │ ensures ▼ host daemon ──► local Omnigent server (AP) │ spawns ▲ ▼ connect-RPC │ HTTP runner ── launches ──► agy (TUI, in tmux) │ │ ├── write path: type web turns into the TUI │ (tmux bracketed paste → real USER_INPUT step) └── read path: RPC read driver mirrors agy's trajectory steps back into the session ``` Three transports, easy to confuse: 1. **Write path = typing into the TUI.** Every web/mobile turn is *typed* into the agy pane via tmux (`inject_user_message_via_tui`), creating a real `CORTEX_STEP_TYPE_USER_INPUT` step on the **same** cascade the TUI shows (#1156/#1158). It is **not** delivered over `SendUserCascadeMessage` (that headless RPC path was retired; the `antigravity_native.py` module header still says "delivered via the RPC" — that's stale doc-lag, the executor is authoritative). 2. **Read path = RPC.** `antigravity_native_reader` polls/streams agy's connect-RPC trajectory steps and mirrors them into the Omnigent session. 3. **Control = RPC.** Interrupt is `CancelCascadeSteps`; a tool/permission prompt is answered via `HandleCascadeUserInteraction` (surfaced as an Omnigent elicitation). ## Prerequisites (check these first) 1. **You're on the branch you want to test**, running from that checkout (`.venv/bin/omnigent` / `.venv/bin/python` from this repo). 2. **The `agy` CLI is on PATH** (or at `~/.local/bin/agy`) — the harness can't launch without it: ```bash which agy || ls -l ~/.local/bin/agy agy --version # install if missing (shell installer, NOT npm): # curl -fsSL https://antigravity.google/cli/install.sh | bash # then restart shell .venv/bin/python -c "from omnigent.onboarding.harness_readiness import harness_is_configured; print('antigravity-native ready:', harness_is_configured('antigravity-native'))" ``` 3. **Configure the connection being tested.** Native agy supports OAuth or a Gemini API key/gateway. Use `omni setup` for a saved key, native Gemini gateway, or Databricks profile; follow the [gateway guide](../../../docs/native-agy-gateways.md) and use a fresh isolated daemon. `GEMINI_API_KEY` and `GOOGLE_GEMINI_BASE_URL` are also supported, subject to the documented saved-credential precedence. For the OAuth path, run bare `agy` once and complete browser sign-in. Verify OAuth separately (no secrets printed): ```bash .venv/bin/python -c "from omnigent.onboarding.gemini_auth import gemini_login_detected; print('agy oauth token present:', gemini_login_detected())" agy models # exits 0 and lists models only when signed in; else 'Please sign in' ``` `False` / non-zero → run `agy` once and sign in. agy's token lives under `~/.gemini` (`oauth_creds.json` on macOS through 1.0.10, `antigravity-cli/antigravity-oauth-token` on Linux); agy 1.1.7+ on macOS writes no token file and keeps the credential in the Keychain, which is why `gemini_login_detected()` falls back to `agy models` there. 4. **`tmux` is on PATH.** The agy terminal is a runner-owned tmux pane; the CLI attaches to it and the executor drives it via `tmux send-keys` (`_preflight_local_tools` hard-fails without tmux). 5. **Network egress to the selected backend or gateway.** A turn that hangs / fails to connect on a locked-down host is usually egress, not a harness bug. > agy is a standalone binary. OAuth needs no gateway configuration; gateway > tests must verify the selected endpoint receives the main and auxiliary requests. ## Step 1 — start a local server (real server + runner) ```bash cd /path/to/omnigent .venv/bin/omni server --background # detached managed server on a free loopback port .venv/bin/omni server status # prints the URL, e.g. http://127.0.0.1:6767 SERVER=http://127.0.0.1:6767 # use the printed URL below curl -s "$SERVER/health" # {"status":"ok"} ``` (`omnigent antigravity --server ""` also auto-spawns a persistent local server and uses it — handy for a one-shot manual run, but a known `$SERVER` URL is better for scripted API observation below.) ## Step 2 — launch the agy terminal against the local server `omnigent antigravity` **attaches an interactive TUI**, so run it where you can hold it open. Two patterns: **A. Background terminal (recommended for scripted drives).** Launch in one terminal, drive/observe from another: ```bash .venv/bin/omnigent antigravity --server "$SERVER" 2>&1 # attaches the agy TUI; leave it running # add a model: --model gemini-2.5-pro ; pass-through agy args go at the end ``` It prints `Web UI: <url>` and a resume hint to stderr — grab the conversation id (the `…/c/<conv_…>` segment) for the API calls below: ```bash CONV=conv_xxxxxxxx # from the "Web UI:" line / resume hint ``` **B. PTY driver (fully automated).** Drive it under `pexpect` like the `claude-native-e2e-test` skill's `cuj_driver.py`: spawn `omnigent antigravity --server <url>` in a PTY with `cwd=<checkout>`, capture the conv id from the printed URL, then drive/poll the API, then **tear down the whole process tree** (see Teardown — a pexpect Ctrl-C only *detaches* tmux). > The runner **owns** the agy terminal: binding a runner auto-creates the > antigravity terminal for the session, and the CLI *reattaches* rather than > launching its own. Don't hand-launch a second `agy` against the same session — > a double launch 500s and clobbers the runner's bridge state (web-turn injection > then fails "bridge state is missing"). ## Step 3 — drive a turn (and smoke-test) **Via the web path (exercises `AntigravityNativeExecutor`).** Post a user message to the running session; the runner routes it to the harness, whose `_deliver` types it into the agy TUI (real `USER_INPUT` step): ```bash curl -s -X POST "$SERVER/v1/sessions/$CONV/events" \ -H 'content-type: application/json' \ -d '{"type":"message","data":{"role":"user","content":[{"type":"input_text","text":"Reply with exactly the single word: PONG"}]}}' ``` Then **observe** the mirrored transcript (the RPC read driver posts agy's steps back): ```bash sleep 25 curl -s "$SERVER/v1/sessions/$CONV/items" | python -m json.tool | tail -40 ``` A healthy run shows your `user` message **and** a non-empty `assistant` reply (`PONG`) mirrored into the session — proving the full stack: server → runner → executor → tmux paste → agy turn → connect-RPC read driver → transcript mirror. You'll also see the prompt + reply render in the attached agy TUI (parity is the whole point of the TUI-typing write path). - **Type-driven smoke:** instead of the POST, type a prompt directly in the attached agy TUI and confirm it answers + mirrors to `…/items`. - **Model:** select a model with agy's TUI `/model`; the next web turn echoes that choice (the executor reads it from the latest `USER_INPUT` step). ## Inspect the bridge (debugging) Per-session bridge state lives under a hashed dir (keyed by *bridge id*, which defaults to the Omnigent conversation id): ```bash .venv/bin/python -c "from omnigent.antigravity_native_bridge import bridge_dir_for_bridge_id as d; print(d('$CONV'))" # ~/.omnigent/antigravity-native/<sha256(bridge_id)[:32]>/ # state.json <- {session_id, conversation_id (agy's real UUID once minted), active_turn_id} # tmux.json <- {socket_path, tmux_target} the executor types into (send-keys) # bridge.json <- token for the Omnigent MCP relay (sys_* tools) # agy-home/.gemini/... <- per-session ISOLATED HOME: a COPY of your OAuth token # + onboarding markers + config/mcp_config.json (relay) ``` Key facts: - agy mints its **own** UUID cascade; a fresh launch seeds an `agy_conv_*` **placeholder** until cold-start `StartCascade`s the real id and writes it to `state.json` (and PATCHes it as `external_session_id`). RPC calls against a placeholder are skipped — "not ready yet". - The **isolated HOME** (`agy-home/`) is why your real `~/.gemini` is never touched: the relay's `mcp_config.json` and agy's per-session state live there. agy's `/mcp` panel should show `✓ omnigent` with the `sys_*` tools. - Env vars: `HARNESS_ANTIGRAVITY_NATIVE_BRIDGE_DIR`, `HARNESS_ANTIGRAVITY_NATIVE_REQUEST_SESSION_ID`. ## Targeted scenarios | Goal | How | |------|-----| | Web→TUI delivery | POST a message (Step 3); confirm it renders in the agy TUI AND mirrors to `…/items` | | Native tools (shell/edit/read) | prompt agy to create→read→edit a file + run a command; confirm it touches disk | | Omnigent MCP relay (`sys_*`) | in the agy TUI run `/mcp` → expect `✓ omnigent`; prompt agy to `sys_session_list` / spawn a sub-agent | | Permission elicitation | with a tool that needs approval, agy's `request-review` surfaces as an **Omnigent elicitation** (interaction bridge); answer it in the web UI and confirm the tool runs | | Interrupt | mid-turn, hit stop in the UI → `CancelCascadeSteps` (RUNNING cascades only; a step WAITING on an interaction is unblocked by a DENY, not cancel) | | Model echo | `/model` in the TUI, then a web turn — confirm the new model is used (latest `USER_INPUT` step's `planModel`) | | Resume | stop, `omnigent antigravity --server "$SERVER" --resume "$CONV"`; `--resume` (no value) opens the antigravity-native picker | | Concurrency / leaks | drive several sessions; sweep for orphaned `agy` / tmux after teardown | ## Gotchas (these cost real time) 1. **It's a TUI, not `omni run`.** Use `omnigent antigravity`. The executor only delivers into the live agy pane — agy must be running (attached) for a turn to process. 2. **`config.yaml`'s `server:` defaults to a remote server.** Always pass `--server "$SERVER"` (or `--server ""` for local). If a *local* server rejects `antigravity-native`, it's stale — restart it from your checkout (allowlist: `omnigent/spec/_omnigent_compat.py`). 3. **Check the selected credential path.** A saved Gemini default outranks ambient keys and OAuth. OpenAI Responses endpoints are incompatible with native Gemini, even if they serve a Gemini model. Use the gateway guide above. 4. **tmux must be reachable from the CLI process** for the direct attach; the executor's send-keys run on the runner side against the advertised socket. 5. **Isolated HOME.** Don't expect your real `~/.gemini` to change — agy runs under `<bridge_dir>/agy-home`. Look there (and `~/.gemini/antigravity-cli` for agy's own conversation store) when debugging. 6. **Don't double-launch agy** for a session — the runner owns the terminal (see Step 2). 7. **Turns take ~20–120s** — wrap scripted waits/`timeout` generously. 8. **Never print/echo the OAuth token.** Use the boolean/`agy models` probes. ## Code & tests - **Executor (write path — types into the TUI):** `omnigent/inner/antigravity_native_executor.py` - **Harness wrap (`harness: antigravity-native`):** `omnigent/inner/antigravity_native_harness.py` - **CLI launch / daemon-runner / tmux attach:** `omnigent/antigravity_native.py` (`run_antigravity_native`); CLI command `antigravity(...)` in `omnigent/cli.py` - **agy argv / auth-mode / permission flag:** `omnigent/antigravity_native_launch.py` - **Bridge (state, tmux delivery, isolated HOME, MCP relay):** `omnigent/antigravity_native_bridge.py` - **connect-RPC client (port discovery, send/cancel/interaction):** `omnigent/antigravity_native_rpc.py` - **RPC read driver (trajectory mirror):** `omnigent/antigravity_native_reader.py` - **Steps / interactions / audit:** `omnigent/antigravity_native_steps.py`, `omnigent/antigravity_native_interactions.py`, `omnigent/antigravity_native_audit.py` - **OAuth detection:** `omnigent/onboarding/gemini_auth.py` - **Design/plan docs:** `docs/antigravity-native-rpc-core-design.md`, `docs/antigravity-native-rpc-core-plan.md` ```bash .venv/bin/python -m pytest \ tests/harnesses/antigravity_native/test_antigravity_native.py \ tests/harnesses/antigravity_native/test_antigravity_native_bridge.py \ tests/harnesses/antigravity_native/test_antigravity_native_launch.py \ tests/harnesses/antigravity_native/test_antigravity_native_rpc.py \ tests/harnesses/antigravity_native/test_antigravity_native_reader.py \ tests/harnesses/antigravity_native/test_antigravity_native_steps.py \ tests/harnesses/antigravity_native/test_antigravity_native_interactions.py \ tests/harnesses/antigravity_native/test_antigravity_native_audit.py \ tests/inner/test_antigravity_native_executor.py -q ``` ## Bug-bash (fan out) Stress the harness against the same `$SERVER`: the web→TUI delivery path (lost / duplicated turns, the attended-TUI paste race), the RPC read mirror (does every agy step reach `…/items`? duplicates after a reader restart?), the MCP relay (`sys_*` reachable + gated), permission elicitations, interrupt (`CancelCascadeSteps`) vs. a WAITING-on-interaction step, model echo, resume, and orphaned `agy`/tmux after teardown. Cross-check the API — a start failure can leave the TUI empty while the session records an error. ## Watch-outs from the code (verify live) - **Placeholder until cold-start.** Before agy mints its real cascade id, bridge state holds an `agy_conv_*` placeholder and RPC is skipped; a turn fired too early just queues into the TUI. - **Permission gating is all-or-nothing + post-hoc.** agy honors only `--dangerously-skip-permissions` (no firing pre-tool hook), so a headless launch auto-bypasses and the genuine Omnigent gate is the elicitation + post-hoc audit (`antigravity_native_audit`), not a per-tool pre-empt.
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기