AgentCanvas / Pages / Developer Guide / Nodesets / Method / NavGPT
2026-06-20

NavGPT (Zhou et al., AAAI 2024; repo GengzeZhou/NavGPT) is the original "LLM as navigator" agent: a GPT-4 ReAct loop picks viewpoint IDs on the MP3D graph via action_maker — the released config's sole tool, which already teleports to any viewpoint in the scan (back_tracer rides the non-default tool-chain path) — over text observations built from offline BLIP-2 captions and object detections. This page documents the navgpt_mp3d_tools port driving env_mp3d in navgpt_mp3d.json (the paper-faithful mainline), plus the in-house NavGPT-CE variant (navgpt.py + navgpt_ce.json, continuous env — a derived design, not a port).

At a glance
UpstreamNavGPT (Zhou et al., AAAI 2024) — repo GengzeZhou/NavGPT pinned @ b3fc8a2 (MIT). Core: nav_src/agent.py (ReAct agent, scratchpad), nav_src/prompt/planner_prompt.py (VLN_GPT4_PROMPT et al.), nav_src/NavGPT.py. Author is a direct collaborator — treat as in-house-adjacent upstream.
Env consumedenv_mp3dreset (metadata, n_headings 12), observe_navigable / observe_panorama, step_waypoint (viewpoint-ID teleport; success/error/turned_angle extras), evaluate (gym-like contract). CE variant: env_habitat step_discrete.
FM consumedbuilt-in llmCall — MP3D graph pins profile gpt-5-mini · temp 1.0 · max_tokens 2000 · stop: null (the gpt-5 reasoning-model convention — temp≠1.0 or a small max_tokens silently return empty, see platform/project_gpt5_llmcall_params.md); upstream ran GPT-4 · temp 0 — model swap is §3C. Prompt rides orchestrator_llm.config.template
Method nodesetsnavgpt_mp3d_tools (11 nodes, local mode: paper caches, pure FM glue — base64 adapter / caption + detection formatters — legacy R-CNN alternate, format/parse/scratchpad) + navgpt (3 CE nodes: action format skill, keyword parse, history formatter). Online captioning/detection ride the generic model_blip2 / model_instructblip / model_grounding_dino wrappers since the TODO #56 extraction (2026-07-04)
StateMP3D graph: all agent memory rides the loop pivots (scratchpad + init_observation as iterOut persist ports); CE variant stores action_history in graph_state
Graphsworkspace/graphs/vln/unverified/navgpt_mp3d.json (22 nodes, 58 edges, step_budget 10 = upstream max_iterations) · navgpt_ce.json (25 nodes, 32 edges, step_budget 150)
Fidelityfaithful with justified deviations (inventory-first re-audit 2026-06-20 against b3fc8a2, walked cold from parser.py's released config): prompt skeleton = VLN_GPT4_PROMPT with recorded anti-revisit / back_tracer hardening (§3D); scratchpad mechanics mirror _construct_scratchpad incl. the 7000-char cap; step budget corrected 15→10 to match max_iterations; the GPT-4→gpt-5-mini model swap is a recorded cost/access divergence (§3C). E bucket now empty — the former CE-graph dead-planner_llm defect was removed this pass (§3E).
StatusBoth graphs unverified since the 2026-06-09 gym migration. No eval run currently survives on disk — pre-May archives were pruned 2026-05-21 (§4).

1. Upstream method analysis (Zhou et al. 2024)

Upstream NavGPT is a langchain ReAct agent (nav_src/agent.py) on the MatterSim viewpoint graph. The released default in parser.py is use_single_action=True, use_tool_chain=False, use_relative_angle=True, load_instruction=True — a single LLM with everything in one prompt (VLN_GPT4_PROMPT for gpt-4, else VLN_GPT35_PROMPT), tool set [action_maker] only, and max_iterations=10 (parser.py:42, :17, :21). The modular multi-LLM chain (PLANNER_PROMPT / HISTORY_PROMPT / BACK_TRACE_PROMPT / orchestrator variants in the same file, the action_chain / history_chain / plan_chain + back_tracer tool) only fires under use_tool_chain — it is dead code at the default eval. Per step:

  1. Offline perception (preprocessing, not in the loop): BLIP-2 ViT-G FlanT5-XL captions the egocentric views of every viewpoint; Faster R-CNN (Visual Genome vocabulary) detects objects within 3 m. The rollout reads these caches — no vision model runs at navigation time.
  2. Observation text: per-direction scene descriptions + object lists + navigable viewpoints with relative orientation ("left 90", …) and distance.
  3. ReAct prompt (VLN_GPT4_PROMPT): instruction + initial observation + the running scratchpad; the LLM answers Thought / Action / Action Input with tools action_maker or back_tracer, or stops with Final Answer: Finished! (agent.py:44).
  4. Parse: Final Answer regex (agent.py:208) else Action/Action Input extraction; a missing Action Input is a format error fed back to the model.
  5. Scratchpad (_construct_scratchpad, agent.py:117–130): appends each step's log; only the latest step keeps the full observation — earlier action_maker steps are demoted to one-line history summaries; the whole pad is tail-truncated to MAX_SCRATCHPAD_LENGTH = 7000 chars (:46, :136); init_observation is swapped to history[0] after step 0 (get_full_inputs).
  6. Act: the viewpoint ID teleports the agent via MatterSim; back_tracer may target any previously visited viewpoint (non-adjacent allowed).
offline preprocessing BLIP-2 + R-CNN cachescaptions · objects ≤3 m observation textper-direction + navigable ReAct promptVLN_GPT4_PROMPT MatterSim graphnavigable viewpoints GPT-4 calltemp 0 · greedy parse Thought/ActionFinal Answer :208 scratchpad · history _construct_scratchpad :117 cap 7000 chars · short-format demote langchain agent state, in-process teleport to viewpointaction_maker / back_tracer viewpoint ID scratchpad appenddemote prior obs new observation Final Answer: Finished!or max iterations R2R evalSR · SPL · nDTW Finished! ReAct loop — next Thought/Action with the updated scratchpad simulator side agent / preprocessing fn GPT call stop condition agent state data flow state read/write ReAct loop (next step)

1.1 Upstream invariants worth marking

2. The AgentCanvas port (navgpt_mp3d)

The mainline port reproduces the single-LLM VLN_GPT4_PROMPT configuration on env_mp3d, run on gpt-5-mini (upstream's GPT-4 is the reference; §3C). The ReAct prompt rides orchestrator_llm.config.template; the langchain agent loop becomes the graph loop (step_budget 10 = upstream max_iterations), with the scratchpad as an iterOut persist port and scratchpad_writer reproducing _construct_scratchpad's short-format demotion + 7000-char cap (_MAX_SCRATCHPAD_LENGTH, navgpt_mp3d_tools.py:1292). Perception is the paper's own offline artifacts, served by paper_objects_cache / paper_captions_cache nodes (1916-class object vocabulary, ~7.2 objects/viewpoint; BLIP-2 captions + summaries). The nodeset also ships online alternates (BLIP-2, InstructBLIP, COCO R-CNN, open-vocab detector) — none are instantiated in the reference graph.

2.1 Per-step flow

env_mp3d + paper caches paper caches ×2objects · captions (offline) observation_format8-compass + navigable ReAct templateorchestrator_llm.config observe_navigableenv_mp3d · heading orchestrator_llmgpt-5-mini · t1.0 · 2000 parse_actionviewpoint ID / Finished loop-pivot carry scratchpad · init_observation iterOut persist ports (no graph_state) cap 7000 · Visited Viewpoints line step_waypointteleport · success/error viewpoint ID scratchpad_writerdemote + visited line post-move obs + format iterOut · stopstep_waypoint.terminated evaluateenv_mp3d · final_stop final_stop (post-loop) iterOut → iterIn — scratchpad + init_observation persist across steps env_mp3d node navgpt_mp3d_tools node LLM call loop control pivot-carried state data wire state access loop-back (iterOut → iterIn)

Drawn simplified: the init chain (reset → init_observe → init_format → init_observation, which builds the step-0 pad and history-0 line) and the duplicated step-side cache/observe/format chain are collapsed into single boxes; the caches gate the observe nodes via trigger wires so the formatter always sees cache text. Termination: step_waypoint.terminated → iter_out.stop (step budget 10 = upstream max_iterations); post-loop iter_out.final_stop → evaluate.trigger — the sound pivot-rooted shape. All agent memory crosses iterations through the two persist ports; this graph uses no graph_state container.

2.2 Node inventory (navgpt_mp3d_tools — 11 nodes)

NodeRoleIn reference graph?
…__paper_objects_cache / …__paper_captions_cacheServe the paper's offline artifacts per (scan, viewpoint): 1916-class objects (~7.2/viewpoint) and BLIP-2 captions + 1-line summaryYes — ×2 each (init + step)
…__observation_format8-compass observation text: per-direction descriptions, objects, navigable viewpoints with relative angle + distanceYes — ×2 (init + step)
…__init_observationStep-0 pad: initial observation + history_0 + scratchpad seed (upstream history[0] / get_full_inputs swap)Yes
…__parse_actionFinal Answer / Action Input extraction → viewpoint ID or stop (upstream agent.py:208 semantics)Yes
…__scratchpad_writerAppend Thought/Action/Observation; demote prior full obs to one-liners; rewrite the Visited Viewpoints line; 7000-char capYes
…__get_instructionInstruction accessor (legacy)No
…__views_to_base64model_blip2__caption…__format_captionsOnline captioning alternate (replicates the offline BLIP-2 pass at runtime; generic wrapper + pure glue, byte-equal to the retired in-nodeset chain 3/3)No — alternates only
…__fasterrcnn_detect (legacy) / model_grounding_dino__detect (hf_tiny) → …__format_detectionsOnline detection alternates (COCO 91-class; open-vocab ≈ VG/BUTD via the generic wrapper + pure formatter)No — alternates only

2.3 State & memory

MP3D graph: scratchpad and init_observation are iterOut persist ports — the langchain agent's in-object state became pivot-carried wire values; nothing lives in a graph_state container. The cumulative visited-ID list is embedded in the scratchpad text itself (the "Visited Viewpoints" line), re-extracted and re-rendered each step precisely so it survives the 7000-char tail truncation (rationale recorded inline, navgpt_mp3d_tools.py:1671–1683). CE variant: parse_action appends {step, action, action_name, thought} to graph_state["action_history"]; format_history renders the last max_entries (default 15) with older steps elided.

2.4 Boundary contract

Local-mode nodesets (no server_python): the paper-cache and format/parse/scratchpad nodes are pure text plumbing; the optional online vision nodes lazy-load their models into the backend GPU. Env side: env_mp3d per ADR-server-003 (subprocess_per_worker, MatterSim batch 1) — step_waypoint keeps the navgpt-specific extras (success/error/turned_angle/new_viewpoint) that scratchpad_writer folds into the pad. The LLM is a plain llmCall; the ReAct prompt lives in graph config, not in a nodeset constant — prompt edits are graph edits.

2.5 Prompt assets

The system prompt is orchestrator_llm.config.template in navgpt_mp3d.json, derived from upstream VLN_GPT4_PROMPT (nav_src/prompt/planner_prompt.py). Verbatim-preserved: the embodied-agent framing, orientation conventions, the 3-m stop rule, the strict-viewpoint-ID warning, the full ReAct format block, and the closing scaffold (Thought: I should start navigation according to the instruction, {scratchpad}). Deliberately rewritten (recorded — §3D): the advisory anti-revisit sentence became a hard Visited Viewpoints contract, and back_tracer is reinstated with inline tool descriptions. CE variant prompts (5 llmCall templates) are in-house text with upstream echoes (its planner mirrors PLANNER_PROMPT's instruction-decomposition idea); the 3-node navgpt.py nodeset carries the CE action-format constant.

2.6 The NavGPT-CE variant (derived design, not a port)

navgpt_ce.json moves the idea to continuous VLN-CE — a setting upstream never shipped, so no fidelity verdict applies; it is audited only doc↔artifact. Structure: a 4-LLM pipeline per step — vlm_caption (panorama composite → scene text, temp 0.2), obs_summary_llm, orchestrator_llm (chooses FORWARD/LEFT/RIGHT/STOP; system prompt = the navgpt__action_output_format skill constant), history_update_llm, plus navgpt__parse_action (keyword regex, fallback FORWARD) into env_habitat.step_discrete; budget 150; termination step.terminated → iter_out.stop, post-loop final_stop → evaluate. It echoes upstream's modular chain (history LLM) rather than the GPT-4 single-prompt line. The previously-flagged dead planner_llm node was removed 2026-06-20 (§3E), trimming the graph to 25 nodes / 32 edges.

3. Delta vs upstream — five buckets (MP3D mainline)

Each row carries an equivalence icon (orthogonal to the bucket letter — the letter says why it differs, the mark says whether behaviour changed): 🟢 equivalent (identical or semantically identical behaviour) · 🟡 near-equivalent (same intent; a mechanism, library, or edge case differs — output usually matches) · 🟠 divergent (behaviour can differ — by design or, rarely, a defect). A genuine defect is a 🟠 row in bucket E with a severity — never ❌/🔴.

A. Preserved verbatim

Equiv.ElementUpstream anchorHow preserved
🟢ReAct prompt skeleton (framing, orientations, 3-m rule, tool format block, scaffold seed)VLN_GPT4_PROMPT, planner_prompt.py:206Same paragraphs in orchestrator_llm.config.template (re-diffed 2026-06-20; the only deltas are the anti-revisit / back_tracer region — §3D)
🟢Stop protocol Final Answer: Finished!agent.py:44, :208parse_action stop detection (tolerant superset: also bare STOP / FINISHED)
🟡Scratchpad mechanics: latest-step-full / earlier-steps-demoted, 7000-char tail cap, init_observation → history_0 swap_construct_scratchpad agent.py:117–130, :46, get_full_inputs :141scratchpad_writer (_demote_last_full_obs, _MAX_SCRATCHPAD_LENGTH=7000 at :1292), init_observation node. 🟡: the live step also front-loads the turned_angle+summary line (upstream carries that for demoted steps only) — the next-step demote pass collapses both to the same end-state
🟢Observation format: 8-compass directions, relative left/right angles, objects-in-3 m dict, navigable-per-sectormodify_heading_angles agent.py:251–327_format_observation_compass (:1784) — byte-identical on matched-unit inputs
🟢Step budget = upstream max_iterationsparser.py:21 (default 10) → AgentExecutorstep_budget: 10 (corrected 15→10 this pass — the prior 15 was langchain's own default, a silent drift)
🟢Offline-perception regime (captions + ≤3 m objects, no runtime vision)ImageObservationsDB, preprocessing scripts + cachespaper_objects_cache / paper_captions_cache serve the paper's own released artifacts

B. Forced by substrate (script → typed graph)

Equiv.UpstreamPortWhy forced
🟢langchain agent object + in-process loopGraph loop; scratchpad/init_observation as iterOut persist portsCross-iteration state must ride pivots
🟢Offline preprocessing run before evalCache nodes keyed by (scan, viewpoint) inside the loopPerception must be a wire-visible producer; same artifacts, node-shaped
🟢One Python call stack11-node split (format / parse / scratchpad / caches / init)AAS search granularity; each stage independently swappable
🟢MatterSim driven inlineenv_mp3d.step_waypoint over a wire (ADR-server-003 subprocess)Env/method process split

C. Forced by environment / cost

Equiv.UpstreamPortReason
🟠Planner LLM = gpt-4 · temperature 0 (deterministic greedy) · no max_tokens caporchestrator_llm = gpt-5-mini · temperature 1.0 · max_tokens 2000 · stop: nullGPT-4 at this access/cost tier is reserved for the paper reference; gpt-5-mini is the repo-standard accessible substitute (every sibling graph — mapgpt / discussnav / smartway / aoplanner — uses it). temp 1.0 / max_tokens ≥ ~2000 / no stop are forced, not chosen: a gpt-5 profile silently returns empty otherwise (platform/project_gpt5_llmcall_params.md; every working gpt-5 graph drops stop). 🟠 because temp 0 → 1.0 trades determinism for sampling — trajectories can differ. User decision, this session (2026-06-20).
🟡VG/BUTD Faster R-CNN for fresh scansOnline alternates approximate it (COCO 91-class or open-vocab) — shipped, not in the reference graphOriginal detector stack is impractical to rehost; the paper caches make it moot for R2R scans (reference graph uses the released caches, so this is dormant)
🟢Episode-long ReAct session in one API conversationmode: single_turn per step with the scratchpad re-sentllmCall is stateless; equivalent context by construction

D. Intentional divergences

Equiv.UpstreamPortRationale (recorded where)
🟠Advisory anti-revisit ("encouraged … avoiding revisiting by comparing previous Action Inputs") — no visited list renderedHard contract: a Visited Viewpoints line is rendered at the pad's tail every step; the prompt forbids picking listed IDs as an action_maker inputRecorded inline in scratchpad_writer (navgpt_mp3d_tools.py:1676–1684 — incl. why the cumulative list must survive the 7000-char truncation) and in the template text itself. 🟠: a hard ban changes trajectories vs the advisory original.
🟠back_tracer is absent from the released single-action tool set (tools=[action_maker], agent.py:588); it lives only on the dead use_tool_chain pathback_tracer reinstated as a second named tool, inlined into the template ("Move back to any previously visited viewpoint … Use this when you realize you have wandered off-track")Functionally a prompt-level label: parse_action extracts one viewpoint ID regardless of tool name, and step_waypoint teleports to any visited ID — mirroring upstream makeAction (env.py:70), which already jumps to any in-scan viewpoint. Recorded in the template + this audit.
🟢step_waypoint extras (success/error/turned_angle) folded into the padFailed-move feedback the upstream sim handled implicitly (agent.py:399–404); declared in node ports

E. Unexplained / defects

Equiv.#FindingDetailSeverity
🟠E1Fixed 2026-06-20 — dead planner_llm node in navgpt_ce.jsonThe CE graph instantiated a planner_llm (instruction-decomposition prompt, fed by episode_info.instruction) whose response had no outgoing edge — one wasted LLM call per episode, no behavioural effect. Removed this pass (node + its incoming edge + its graph_state binding; CE graph 26→25 nodes, 33→32 edges).Closed. Deletion was behaviour-preserving (the only output had no consumer).

E bucket empty for the MP3D port. Probed cold from the upstream release this pass: the parser.py released config (single-action, action_maker-only, max_iterations=10) → mapped the live ReAct loop, not the dead use_tool_chain path; prompt re-diffed against VLN_GPT4_PROMPT — deltas localize entirely to the recorded anti-revisit / back_tracer region (§3D); modify_heading_angles formatting re-checked against _format_observation_compass (byte-identical on matched units); _construct_scratchpad demote + 7000-char cap + get_full_inputs init-swap matched (the swap is realized by the iterIn pivot wiring init_history_0 → iter_out.init_observation); step budget reconciled to max_iterations (15→10); stop-string set is a tolerant superset of Final Answer; paper caches are the released artifacts, not re-generated approximations. No equivalence unit test exists for either nodeset — eval parity is the only executable check, and none is currently on disk (§4); the next gpt-5-mini run is the evidence baseline.

4. Evaluation

WhatNumberEvidence
Paper-reported (NavGPT, GPT-4, R2R val_unseen)SR ≈ 0.34Paper headline as commonly cited; not re-verified against the PDF this audit — treat as provisional until a closure run exists
Our runsnone on diskEarlier navgpt batches predate the 2026-05-21 archive prune (archive_outputs --prune); outputs/eval_runs/ currently holds no navgpt run. The next run is the evidence baseline.

Current status: both graphs sit in workspace/graphs/vln/unverified/ — rewired in the 2026-06-09 gym migration (bundle nodes → observe_* + step_waypoint/step_discrete; termination via iter_out.stop; evaluate post-loop via final_stop, the sound shape). The MP3D graph now drives gpt-5-mini (temp 1.0 / max_tokens 2000 / step_budget 10), so the next run is the evidence baseline — run /experiment:run navgpt-mp3d navgpt_mp3d episode_count=10. R2R val_unseen stratification applies to any future headline number (front-loaded easy scans — use the MapGPT72 cut for paper-comparable figures).

5. Usage

# load — method nodesets are local-mode; env_mp3d is server-mode (per-worker MatterSim)
POST /api/components/nodesets/navgpt_mp3d_tools/load
POST /api/components/nodesets/navgpt/load                     # CE variant nodes
POST /api/components/nodesets/env_mp3d/load?mode=server

# graphs
workspace/graphs/vln/unverified/navgpt_mp3d.json
workspace/graphs/vln/unverified/navgpt_ce.json

# batch eval — graph-only form: /experiment:run <profile> <graph_name> [key=value ...]
/experiment:run navgpt-mp3d navgpt_mp3d episode_count=10

6. What this nodeset is NOT

7. Source files

FilePurpose
workspace/nodesets/method/navgpt_mp3d_tools.pyThe MP3D port — 11 nodes, 2126 lines (caches, format, parse, scratchpad, online alternates)
workspace/nodesets/method/navgpt.pyCE variant nodes — action-format skill, keyword parse, history formatter (270 lines)
workspace/nodesets/env/env_mp3d/Env side — MatterSim graph, step_waypoint + navgpt extras
workspace/graphs/vln/unverified/navgpt_mp3d.jsonReference MP3D graph (§2.1 authority; ReAct template in orchestrator_llm.config)
workspace/graphs/vln/unverified/navgpt_ce.jsonCE variant graph (4-LLM pipeline, §2.6)
workspace/nodesets/_upstream/navgpt/fetch_upstream.shClones upstream @ b3fc8a2 (MIT) into a gitignored upstream/
AgentCanvas docs