Skip to content

Go2 agentic architecture layers and self-evolution review#2727

Open
z1050297972-spec wants to merge 39 commits into
dimensionalOS:mainfrom
z1050297972-spec:refactor/go2-architecture-layers
Open

Go2 agentic architecture layers and self-evolution review#2727
z1050297972-spec wants to merge 39 commits into
dimensionalOS:mainfrom
z1050297972-spec:refactor/go2-architecture-layers

Conversation

@z1050297972-spec

@z1050297972-spec z1050297972-spec commented Jul 4, 2026

Copy link
Copy Markdown

Hi DimOS maintainers,

I am opening this as a draft PR for architecture review and discussion. The goal is to share my current thinking around a Go2 agentic architecture extension, especially around context scheduling, skill-interface evolution, and reviewable self-evolution artifacts. I am not asking for an immediate merge before the design direction is reviewed.

Architecture overview

The main review figure is below. It combines the repo-wide DimOS runtime architecture with the Go2 agentic extension in one diagram, so the agent layer can be reviewed in the context of blueprints, runtime modules, transports, skills, memory, and robot targets.

DimOS project architecture with Go2 agentic self-evolution extension

Editable SVG source:
https://github.com/z1050297972-spec/dimos/blob/refactor/go2-architecture-layers/docs/reviews/2026-07-05-dimos-agentic-architecture.svg

PNG render in the branch:
https://github.com/z1050297972-spec/dimos/blob/refactor/go2-architecture-layers/docs/reviews/2026-07-05-dimos-agentic-architecture.png

Detailed review notes:

What this branch explores

This branch proposes a more explicit Go2 agentic layering model:

  • Layer 3: Agent Brain: prompt routing, context-provider invocation, feasibility evaluation, MCP/tool selection, outcome recording, causal-state use, and skill-proposal generation.
  • Layer 4: World State: structured runtime/body state, semantic temporal map, spatial/RAG memory access, temporal summaries, and snapshot metadata.
  • Layer 5: Skill Interface: static skill contracts, preflight metadata, argument validation, MCP-tool comparison, and skill proposal artifacts.
  • Layer 6: Robot Body: Go2 connection, sensors/odom, motion-control evidence, and lower-level runtime readiness.

The important design boundary is that self-evolution is represented as reviewable artifacts, not automatic code mutation. The agent can record events and proposals, but those artifacts still need human or downstream tooling review before becoming implementation changes.

Main technical changes

  • Added Go2 self-evolution proposal tools and a local evolution ledger for structured event/proposal artifacts.
  • Added context-provider evidence schemas so selected context, dropped context, source confidence, and policy effects can be reviewed after a task.
  • Added feasibility evaluation surfaces so the agent can classify a requested task as feasible, infeasible, or uncertain using available skills, missing context, and safety risks.
  • Added skill-interface contracts and validation so the agent has a clearer boundary between “existing tool can be used” and “new skill/interface should be proposed”.
  • Added memory/backend status reporting to make it explicit which spatial, temporal, RAG, feedback, outcome, or world-model providers are actually wired and available.
  • Added lightweight causal/world-model state plumbing as an advisory evidence source. This is not a separately trained model in this branch; it is a structured evidence and outcome interface for later learning/review loops.
  • Added optional observability/dashboard contracts, while documenting that the current unitree_go2_agentic blueprint does not wire WebsocketVisModule directly.
  • Expanded English and Chinese review documents with implementation logic, interface inputs/outputs, storage boundaries, decision owners, failure modes, and validation notes.
  • Merged current upstream main into this branch and preserved upstream infrastructure changes while keeping the local Go2 layered architecture work.

Review questions

I would especially appreciate feedback on these points:

  1. Is the Layer 3/4/5/6 boundary compatible with how DimOS maintainers expect agentic robot stacks to evolve?
  2. Should self-evolution artifacts live in a local Git-backed ledger, an existing memory/RAG backend, or both depending on artifact type?
  3. Is the ContextProvider boundary the right place to decide which memory/context is effective, with the LLM remaining the main judgment owner after context is selected?
  4. Is the skill-contract/proposal flow a reasonable way to separate existing skill use from proposing a new skill interface?
  5. Are there parts of this that should be moved out of Go2-specific code into a robot-agnostic agent subsystem?

Validation performed

  • Synced this branch with upstream main at 6e813a72 and resolved merge conflicts while preserving upstream infrastructure updates.
  • Added detailed review docs for both English and Chinese readers.
  • Added deterministic editable SVG architecture figures and PNG renders, then visually checked them for label/arrow/optional-path ambiguity.
  • Parsed the SVG diagrams as XML.
  • Ran git diff --check / git diff --cached --check on the changed docs, SVGs, and changelog updates during the documentation work.
  • Cleaned local runtime noise by ignoring MUJOCO_LOG.TXT.

Notes

This is intentionally opened as a draft PR. I expect some parts may need to be split, renamed, or moved to more general DimOS agent packages after maintainers review the architecture direction.

@z1050297972-spec z1050297972-spec marked this pull request as ready for review July 4, 2026 18:17
@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds Go2 agentic architecture layers and supporting review artifacts. The main changes are:

  • New Layer 3 brain modules for context evidence, routing, skill outcomes, proposals, and causal state.
  • New Layer 4 world-state and temporal-map interfaces.
  • New Layer 5 skill-interface contracts and registry validation.
  • New Layer 6 robot-body state surfaces.
  • Updated MCP outcome recording, direct tool routing, Rerun dashboard wiring, and Go2 architecture docs.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
dimos/robot/unitree/go2/blueprints/layers/layer_3_agent_brain/evolution_proposal.py Proposal files now preserve sequential reused IDs and distinguish normalized filename collisions.
dimos/agents/mcp/mcp_client.py MCP tool calls now record structured skill outcomes with task context for user-triggered calls.
dimos/web/templates/rerun_dashboard.html The Rerun iframe now derives its browser target host from the loaded dashboard page.

Reviews (9): Last reviewed commit: "fix(dashboard): resolve Rerun iframe hos..." | Re-trigger Greptile

Comment thread dimos/web/templates/rerun_dashboard.html Outdated
Comment thread dimos/agents/mcp/mcp_client.py
write_skill_proposal_file derived the artifact path solely from
proposal_id via _safe_filename, then atomically replaced it. A reused
stable proposal_id (e.g. improve_navigation) would silently overwrite
the earlier review artifact, losing the proposal reviewers were meant
to inspect. Mirror the events path's _unique_event_path approach:
append -1, -2, ... when the path exists so both artifacts are kept.
The author's proposal_id stays verbatim in the JSON; only the filename
is disambiguated.
_safe_filename maps every non-alphanumeric character to '_', so
distinct proposal_ids such as skill-v2 and skill.v2 both reduce to
skill_v2 and land on the same path. The prior -N suffix guard only
treated genuine same-id reuses; it would file the second distinct
proposal as skill_v2-1.json, conflating unrelated proposals as
iterations and risking overwrite of the first when ordering changes.

Anchor the stem on an injective digest of the original (un-sanitized)
proposal_id: {slug}-{sha1(id)[:8]}. Distinct ids now always map to
distinct files; the -1/-2 suffix still handles true same-id reuse.
JSON proposal_id stays verbatim. This mirrors how the events path uses
a timestamp prefix to sidestep lossy sanitization.
payload = json.dumps(normalized, indent=2, sort_keys=True) + "\n"
tmp_path = path.with_name(f".{path.name}.tmp-{os.getpid()}")
tmp_path.write_text(payload, encoding="utf-8")
tmp_path.replace(path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Concurrent Proposals Overwrite The path is chosen with _unique_proposal_path() before this replace(), but the final write still overwrites if another agent creates the same filename between the exists() check and the replace. Two concurrent calls with the same stable proposal_id can both choose the base file, both return success, and only the later proposal remains in the ledger. The suffix selection needs to claim the final filename atomically, such as with an exclusive create or a lock around path selection and write.

…ct RPC routing

Direct tool registration was routing calls to skill.class_name/skill.func_name
instead of the module's actual RPCClient.remote_name.  When workers register
with aliased or remapped names the direct path sends tool calls to a route
that does not match the running module, causing failures or empty results.
… hardcoding localhost

The iframe src was hardcoded to localhost:9090 and localhost:9876, ignoring
DIMOS_RERUN_HOST / --rerun-host and listen_host.  When the dashboard is served
from a remote machine the embedded Rerun viewer connects to the browser user's
localhost and the stream never appears.

Read the template at serve time, substitute the correct host and ports
(RERUN_WEB_VIEWER_PORT=9878, RERUN_GRPC_PORT=9877).
write_text() directly on the shared JSON state file is not atomic:
- a crash during write truncates the file
- concurrent agent instances interleave writes, losing transitions

Write to a temp file in the same directory, then os.replace() for an
atomic swap that guarantees readers always see a complete file.
_load_world_model_state_from_path and InterventionLog.load_dict both cleared
in-memory state (transitions, records) before parsing the payload.  If any
item failed to parse the running model was left corrupted.

Build all new objects in temporaries first, swap in only after all parsing
succeeds.  A bad schema, malformed transition, or float() conversion failure
no longer destroys the running model's state.
…k evidence leakage

get_recent_outcomes() filtered only by skill_name, so unrelated tasks shared
outcome history.  When the causal world model recorded a transition without
an explicit outcome_json it fell back to _latest_outcome(skill_name), which
could grab another task's navigate_with_text success/failure and feed it as
evidence for the current task.

Add a 'task' dimension to SkillOutcome, record_skill_outcome, and
get_recent_outcomes.  _latest_outcome now filters by both skill_name and
task so that 'go to kitchen' outcomes never leak into 'go to office'
predictions.
Comment thread dimos/agents/mcp/mcp_client.py
Auto-recorded outcomes from McpClient._record_tool_outcome were missing
the 'task' field, so they were stored with task="".  Later,
_latest_outcome(skill_name, task="go to the kitchen") filtered by the
non-empty task and never matched, causing the causal world model to
record transitions with outcome_success=None (unknown).

Capture the last user input as _last_user_task and inject it into both
_outcome_payload_from_result and _record_tool_exception so auto-recorded
outcomes carry the same task key that _latest_outcome filters by.
Comment thread dimos/web/websocket_vis/websocket_vis_module.py Outdated
…nd address

The server-side resolved host (listen_host=127.0.0.1 or rerun_host) was
used as the iframe target.  When the browser is on a different machine:
- 127.0.0.1 → browser tries to reach its own loopback
- 0.0.0.0 → not a routable address

Use window.location.hostname in JavaScript to build the iframe URL
client-side, so the browser always connects to the same host it used
to load the dashboard page.  Ports (9877 gRPC, 9878 web viewer) are
hardcoded constants matching the Rerun bridge defaults.
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.

2 participants