Skip to content

🖥️ Desktop: blueprint view - #4506

Draft
jeff-hykin wants to merge 126 commits into
jeff/feat/gateway_cloudfrom
jeff/feat/blueprint_view
Draft

jeff-hykin wants to merge 126 commits into
jeff/feat/gateway_cloudfrom
jeff/feat/blueprint_view

Conversation

@jeff-hykin

@jeff-hykin jeff-hykin commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

The blueprint view page, /source, /msgs.js and the cloud login page apps embed.

@github-actions github-actions Bot left a comment •

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.

go2 replay realtime (arm64)

Details
Benchmark suite Current: 8436bc3 Previous: 6de7182 Ratio
peak memory 1749.566 MB 1692.82 MB 1.03
peak threads 366 threads 373 threads 0.98
network (transport) 2731.037 MB 2728.305 MB 1.00
disk write 1.492 MB 1.688 MB 0.88
instructions 137.892 G 137.493 G 1.00

This comment was automatically generated by workflow using github-action-benchmark.

@codecov

codecov Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
7378 1 7377 55
View the top 1 failed test(s) by shortest run time
dimos.e2e_tests.test_dimsim_spatial_memory::test_go_to_the_bed
Stack Traces | 272s run time
lcm_spy = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x7572a8f1b3e0>
start_blueprint = <function start_blueprint.<locals>.set_name_and_start at 0x757137258180>
wait_for_system_ready = <function wait_for_system_ready.<locals>.wait at 0x757137258220>
human_input = <function human_input.<locals>.send_human_input at 0x757137258360>
dim_sim = <dimos.e2e_tests.dim_sim_client.DimSimClient object at 0x7572a914b950>
explore_house = <function explore_house.<locals>.explore at 0x757137258b80>

    @pytest.mark.self_hosted_large
    def test_go_to_the_bed(
        lcm_spy, start_blueprint, wait_for_system_ready, human_input, dim_sim, explore_house
    ) -> None:
        start_blueprint(
            "run",
            "unitree-go2-agentic",
            simulator="dimsim",
        )
        wait_for_system_ready(timeout=300.0)
    
        explore_house()
    
        human_input("go to the bed")
    
>       lcm_spy.wait_until_odom_position(-3.567, -1.332, threshold=2, timeout=180)

dim_sim    = <dimos.e2e_tests.dim_sim_client.DimSimClient object at 0x7572a914b950>
explore_house = <function explore_house.<locals>.explore at 0x757137258b80>
human_input = <function human_input.<locals>.send_human_input at 0x757137258360>
lcm_spy    = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x7572a8f1b3e0>
start_blueprint = <function start_blueprint.<locals>.set_name_and_start at 0x757137258180>
wait_for_system_ready = <function wait_for_system_ready.<locals>.wait at 0x757137258220>

dimos/e2e_tests/test_dimsim_spatial_memory.py:33: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
dimos/e2e_tests/lcm_spy.py:143: in wait_until_odom_position
    self.wait_for_message_result(
        predicate  = <function LcmSpy.wait_until_odom_position.<locals>.predicate at 0x75713746de40>
        self       = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x7572a8f1b3e0>
        threshold  = 2
        timeout    = 180
        x          = -3.567
        y          = -1.332
dimos/e2e_tests/lcm_spy.py:129: in wait_for_message_result
    wait_until(
        event      = <threading.Event at 0x757137f67950: unset>
        fail_message = 'Failed to get to position x=-3.567, y=-1.332'
        listener   = <function LcmSpy.wait_for_message_result.<locals>.listener at 0x75713746e2a0>
        predicate  = <function LcmSpy.wait_until_odom_position.<locals>.predicate at 0x75713746de40>
        self       = <dimos.e2e_tests.lcm_spy.LcmSpy object at 0x7572a8f1b3e0>
        timeout    = 180
        topic      = '/odom#geometry_msgs.PoseStamped'
        type       = <class 'dimos.msgs.geometry_msgs.PoseStamped.PoseStamped'>
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

predicate = <bound method Event.is_set of <threading.Event at 0x757137f67950: unset>>

    def wait_until(
        predicate: Callable[[], bool],
        *,
        timeout: float,
        interval: float = 0.1,
        message: str | None = None,
    ) -> None:
        """Poll ``predicate`` until it returns truthy or ``timeout`` elapses."""
        deadline = time.monotonic() + timeout
        while time.monotonic() < deadline:
            if predicate():
                return
            time.sleep(interval)
>       raise TimeoutError(message or f"Timed out after {timeout}s waiting for condition")
E       TimeoutError: Failed to get to position x=-3.567, y=-1.332

deadline   = 9387825.103747657
interval   = 0.1
message    = 'Failed to get to position x=-3.567, y=-1.332'
predicate  = <bound method Event.is_set of <threading.Event at 0x757137f67950: unset>>
timeout    = 180

.../utils/testing/waiting.py:35: TimeoutError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

…age (a local *.html exclude kept them out)

(cherry picked from commit 996080e2846bf32d2b7d2ce92b9018120622ade6)
(cherry picked from commit c29bf936ab3809e5103d4bca4cec5f3c96aa7401)
… 0.2.160's installer requires them), go2 annotation follows the mls-htc -> hol-path-controller rename
…ams carry their wired name), and Zenoh-pinned topics resolve (a spec's Topic object, minus the dimos/ namespace)
…pans it (touch-action: none, so the browser's own page zoom no longer stacks on the graph's)
…ile asked

TopicWatch subscribed to dimos/** at boot and appended (time, size) for every sample, trimming only in snapshot(),
which nothing called: on the R1 (852 msg/s) the gateway grew ~6 MB/min to 4.1 GB in 12 h. heard() now trims the
window, the subscription starts on the first GET /dimos/topics/rates and stops 60 s after the last one.
…tes once an upload ends, and old jobs when a new one starts
…nd the theme, launch events instead of polling, named intervals, Desktop routes in uses:, no /info range)
… map, not a robot IP (the replay one required an IP it never uses)
…t ../../apps/@launcher/, topics at ../desktop/topics), and dimos.yaml declares them as spec v1.4
… with React mapped at the web workspace root for it
… the raw-url import gets the automatic runtime instead of a bare React.createElement that left the view blank), and the theme is ../../theme.css: the view's path gained a level in the /gateways/ move
…rinted (a run that never started has no log, so Logs became Output and opens the launch's own output, a traceback drawn frame by frame), and on a phone the blueprint keeps a row of its own with the controls sharing the one under it, each the same width whatever its label says; a render that throws now says so instead of leaving the panel blank
…9c5a5c (#4787): this branch's annotation said OccupancyConfig, so blueprint parsing re-validated the serialized HeightCostConfig as the base one and r1pro-nav wouldn't launch (costmapper.config.can_pass_under: Unexpected keyword argument)
… is an older copy of this branch's, so experimental/gateway/, dimos.yaml and docs/usage/gateway.md keep this side (theirs holds nothing newer); pyproject.toml takes main's 0.0.15 and its mkdocs docstring deps with this branch's gateway assets, and uv.lock is relocked on that
… not as the bottom edge of rich's box (its gutters come off, and a wrapped exception is put back together); the first r1pro-nav failure to show it said only a line of box drawing
…es (Desktop keeps one per desktop-gateway tag): dimos.yaml's setup: makes that copy's own light venv and start: passes DIMOS_DIR as --dimos-dir; the checkout is always introspected with this gateway's introspect.py and helpers in its own python (an older experimental/gateway/ in it, tracked or not, is never run); recordings default to the served checkout's, a launch's log dir is its run's, and GET /info's server says the gateway's own dir, commit and tag
…ared config.yaml instead of reading it on a hot path

Desktop writes $DIMOS_HOME/config.yaml and the gateway reads it, but Desktop's
own readers (DIMOS_APP construction, the /recordings routes) are synchronous, so
a blocking request per read is out. The gateway now watches the file and
publishes a bare {"type": "config"} on <ns>/dimos/events/config when the answer
it would give changes, and GET /config is that answer: the file's path and the
recordings directory, read fresh. The event carries no values, so a listener's
cache and the gateway cannot say different things.

The settings a flag can win (zenoh.namespace, dimos-gateway.socket) are left out
of GET /config: they are fixed when the gateway starts, so re-resolving them from
the file would misreport what it is using. GET /info still has the running ones.
…ome this gateway belongs to

Refines the commit before it, which brought `GET /config` and a whole-config
`config` event over from where it was written.

The event is per setting now: `<ns>/dimos/events/config/<setting>`, where
`<setting>` is a key of `GET /config` (`recordingsDir`, `path`), with the payload
`{"type": "config", "setting": "<it>"}`. A listener subscribes to the setting it
actually reads instead of waking, and re-asking, for every change to the file,
and a save that rewrites the file without moving an answer is not news. Still no
value in the payload: `GET /config` stays the one answer, so a listener's cache
and the event can never say different things. Subscribing to all of them is
`<ns>/dimos/events/**` -- a single `*` matches one chunk and would miss these,
which is why `Bus.send` takes the topic's tail.

`DIMOS_APP` is what Desktop starts a component with: which component this is
(`name`) and the home whose config.yaml it reads (`home`), as one JSON object
rather than a variable per setting. `DIMOS_HOME` still works and still means the
same thing, because that is what every Desktop before 0.2.228 sets, and because
someone running the gateway by hand exports it. Unusable JSON is logged and
ignored rather than fatal: what it locates has a default to fall back to.

8.2.0 and not 8.1.0 because 8.1.0 is taken (the gateway running from a copy
apart from the checkout it serves, the commit this is on top of). This is cut
from that line on purpose: tagging the same work off main would have given a
Desktop resolving the newer API a gateway without any of it.

Needed by dim-app v0.25.0's sharedConfig()/watchSharedConfig() and v0.26.0's
watchRecordingsDir().
…ig.py reads config.yaml with it). It only ever arrived through other packages (open3d on Mac and x86), so Desktop's light gateway venv (setup:, from 8.1.0) had none on Linux arm and the gateway would not start
…ateway_fixes' pyyaml and main through it)

# Conflicts:
#	docs/usage/gateway.md
#	experimental/gateway/app.py
#	experimental/gateway/constants.py
#	experimental/gateway/responses.py
#	experimental/gateway/state.py
#	experimental/gateway/store.py
#	experimental/gateway/tests/test_active.py
…r: they run only in simulation, so the Go2 defaults (Run it on Robot, its Robot IP, a replay of a real Go2's odom and camera) don't apply

This branch was successfully deployed

1 active (outdated) deployment
cachix — 4cbe81ba Deployed Oct 25, 2026 by jeff-hykin via cachix-build #14245
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.

1 participant