TASK 14 - Consolidate the submission pipeline into the scene_gemini responder¶
Purpose¶
Wire the three named submission components — frontier exploration +
scene-graph building + Gemini question answering — into a single coherent
responder, and retire the old gemini responder that was not actually wired to
either the shared explorer or the object scene graph.
Problem (before)¶
The gemini responder (GeminiResponder) and the app-level pipeline were two
parallel, unwired designs:
- Double exploration.
compose_gemini.ymlleftXIAO_HEI_EXPLORATION_MAX_WAYPOINTSat its default (100), so the app-levelFrontierExplorerran to completion beforeGeminiResponder.respond()was ever called (the explore branchreturns early andGeminiResponderhas noingest()).GeminiResponderthen explored again internally (its ownperception_responder+GlobalMap, up tomax_explore_ticks) before calling Gemini. Redundant and slow, with two disconnected scenes. - Empty object graph.
GeminiResponderserved an object-less scene: its internal explorer was pure geometric (no detector), andcompose_gemini.ymlran no perception sidecar. Gemini had to infer everything from the panorama — weak for object-reference (which must return a 3D box) and counting.
What changed¶
New responder SceneGeminiResponder (XIAO_HEI_RESPONDER=scene_gemini,
module src/xiao_hei_vln/scene_gemini/), driven by the shared app-level
explorer:
FrontierExplorer (app loop) drives movement
└─ every tick → responder.ingest(snapshot)
└─ perception sidecar (YOLO-World + SAM) → 3D lift → SceneRepresentation
└─ on explorer.is_complete() → responder.respond(snapshot)
└─ serialize the POPULATED scene graph + panorama + occupancy PNG → Gemini
- One exploration pass. The responder exposes
ingest(), so the Task-12 app loop feeds it during the sweep; it never runs its own explorer.respond()is only reached once the sweep is complete, so Task 1 asks Gemini once on the first answer tick and commits (no internalmax_explore_ticksdance). - Real object graph.
ingest()delegates to the sidecar-backedperception.PerceptionResponder, writing labelled, 3D-positioned (and, withXIAO_HEI_OBJECT_MAP=1, 3D-boxed) objects into the sharedSceneRepresentation— the same instanceapp/main.pyowns and the same one serialized to Gemini. So the app-levelscene.update(viewpoints/bounds) and the perception object layer always agree. - Task 2 unchanged in spirit: plan a route via Gemini once, step waypoints.
- API-key leak fixed. The scene_gemini logger config strips
api_keybefore writingsession.json(the old gemini branch wrote it verbatim). - rviz markers now also publish for
scene_gemini(fused object boxes on/perception/objects).
Reused as-is: GeminiEngine / GeminiConfig / prompts / scene_rep
(build_bundle + serialize_for_gemini) / trace, and the whole offline
gemini.batch evaluator.
Retired¶
src/xiao_hei_vln/gemini/responder.py(GeminiResponder) — deleted.tests/test_gemini_responder.py— deleted; replaced bytests/test_scene_gemini.py.docker/compose_gemini.yml— deleted (set the deadgeminiresponder).gemini/__init__.pyno longer exportsGeminiResponder;app/main.py'sgeminibranch is replaced by thescene_geminibranch; theexpected one of:error message updated.
Files¶
New: src/xiao_hei_vln/scene_gemini/__init__.py, .../responder.py,
tests/test_scene_gemini.py, docker/compose_scene_gemini.yml.
Modified: src/xiao_hei_vln/app/main.py, src/xiao_hei_vln/gemini/__init__.py,
.../gemini/engine.py (docstring), .../gemini/batch.py (docstring),
README.md.
Deleted: src/xiao_hei_vln/gemini/responder.py,
tests/test_gemini_responder.py, docker/compose_gemini.yml.
Verification¶
uv run pytest -q→ 461 passed, 1 skipped (studio-zip test). Newtest_scene_gemini.pycovers:ingestbuilds the shared scene without answering; Task-1 numerical/object-reference commit on the first answer tick with the populated graph reaching Gemini; Task-2 plan-once-then-step; Gemini-failure hold+retry; logger lifecycle; reset.ruff checkclean on the new source (src/xiao_hei_vln/scene_gemini/,app/main.py).docker compose -f docker/compose_scene_gemini.yml configvalidates.
Not yet done¶
- Tier-2 live end-to-end on the sim (needs a valid
XIAO_HEI_GEMINI_API_KEYand the perception + sim containers sharing the GPU). This is the real submission smoke test: bring upcompose_scene_gemini.yml, pub one question per task type, confirm the answer routes to the right topic andpredictions.jsonlis written. - Deeper
docs/pages still describe the oldgeminiresponder architecturally (no broken run instructions — those were README-only).