Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dimos/robot/all_blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"drone-agentic": "dimos.robot.drone.blueprints.agentic.drone_agentic:drone_agentic",
"drone-basic": "dimos.robot.drone.blueprints.basic.drone_basic:drone_basic",
"dual-xarm6-planner": "dimos.manipulation.blueprints:dual_xarm6_planner",
"greeter-agentic": "dimos.robot.unitree.go2.blueprints.agentic.greeter_agentic:greeter_agentic",
"keyboard-teleop-a750": "dimos.robot.manipulators.a750.blueprints:keyboard_teleop_a750",
"keyboard-teleop-openarm": "dimos.robot.manipulators.openarm.blueprints:keyboard_teleop_openarm",
"keyboard-teleop-openarm-mock": "dimos.robot.manipulators.openarm.blueprints:keyboard_teleop_openarm_mock",
Expand Down
62 changes: 62 additions & 0 deletions dimos/robot/unitree/go2/blueprints/agentic/greeter_agentic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""Version-controlled copy of the `greeter-agentic` `dimos run` blueprint.

The greeter dog: wander (DimOS patrol) until a person sitting on a chair is
found, pick a random not-yet-greeted one, walk over, circle to face them, and
wave hello -- then resume the patrol. The autonomous loop lives in
``GreeterSkillContainer``; start/stop it via MCP.

Install it next to the stock agentic blueprints in the DimOS source tree and
regenerate the registry:

cp integration/greeter_agentic.py \\
"$DIMOS_HOME/dimos/robot/unitree/go2/blueprints/agentic/"
pytest -o addopts="" \\
"$DIMOS_HOME/dimos/robot/test_all_blueprints_generation.py"

Then (with the `pawtrack` package importable):

PYTHONPATH=src PAWTRACK_MODEL=openai:deepseek-chat \
dimos run greeter-agentic --robot-ip <dog_ip>
dimos mcp call start_greeting # or tell the agent: "go greet people"
dimos mcp call stop_greeting # halt

This is the stock ``unitree-go2-agentic`` general agent **plus** the greeter
skill container -- i.e. a normal Go2 agent that can navigate, speak, run sport
commands, etc., and *also* knows how to greet. It uses the agent's default
general system prompt (no narrow greeter prompt); the agent discovers the
greeting from the skill docstrings (``start_greeting`` / ``stop_greeting`` /
``greeter_status`` / ``wave_hello``) and calls it when asked, like any other
skill. The wander/greet loop itself is autonomous once started. Model defaults
to the agent's default; override with ``PAWTRACK_MODEL``.
"""

from __future__ import annotations

import os

from dimos.agents.mcp.mcp_client import McpClient
from dimos.agents.mcp.mcp_server import McpServer
from dimos.core.coordination.blueprints import autoconnect
from dimos.robot.unitree.go2.blueprints.agentic._common_agentic import (
_common_agentic,
)
from dimos.robot.unitree.go2.blueprints.smart.unitree_go2_spatial import (
unitree_go2_spatial,
)

from pawtrack.greeter_container import GreeterSkillContainer

_MODEL = os.environ.get("PAWTRACK_MODEL")

# Stock unitree-go2-agentic (general agent, default prompt) + the greeter skill.
_agent = (
McpClient.blueprint(model=_MODEL) if _MODEL else McpClient.blueprint()
)

greeter_agentic = autoconnect(
unitree_go2_spatial,
McpServer.blueprint(),
_agent,
_common_agentic,
GreeterSkillContainer.blueprint(),
)
55 changes: 55 additions & 0 deletions hackathon/pawtrack/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# PawTrack Greeter Hackathon Demo

## Overview

PawTrack adds a DimOS / Unitree Go2 autonomous greeter demo. The robot patrols, detects a target such as a person sitting on a chair, tracks it, approaches to a safe standoff, waves, records the visited location, and resumes patrol. The DimOS blueprint is registered as `greeter-agentic`.

Source lives in `hackathon/pawtrack/src/pawtrack`. The runnable DimOS blueprint is placed at `dimos/robot/unitree/go2/blueprints/agentic/greeter_agentic.py` and registered in `dimos/robot/all_blueprints.py`.

## Run

From this DimOS checkout:

```bash
export DIMOS_HOME="${DIMOS_HOME:-$HOME/sam/dimos}"
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 Developer-specific path leaking into shared docs

The default value $HOME/sam/dimos references a developer's personal directory. Anyone cloning the repo and following this README verbatim will resolve to /home/$USER/sam/dimos, which almost certainly does not exist and will cause a confusing failure. The same path also appears in scripts/run_greeter_sim.sh line 22 and in the "Test" block on line 46. The correct default should use the repo root (e.g., $(pwd) or $REPO_ROOT) or leave it as a required export with no silent fallback.

export DIMOS_VENV="${DIMOS_VENV:-$HOME/dimos-env}"
export PYTHONPATH="$DIMOS_HOME/hackathon/pawtrack/src:$DIMOS_HOME:${PYTHONPATH:-}"
source "$DIMOS_VENV/bin/activate"
cd "$DIMOS_HOME"
```

Simulation:

```bash
hackathon/pawtrack/scripts/run_greeter_sim.sh
```

Then in another shell:

```bash
dimos mcp call start_greeting --arg target="a person"
dimos mcp call greeter_status
dimos mcp call stop_greeting
```

Real Go2:

```bash
dimos run greeter-agentic --robot-ip <robot_ip>
dimos mcp call start_greeting --arg target="a person sitting on a chair"
dimos mcp call stop_greeting
```

## Test

```bash
export DIMOS_HOME="${DIMOS_HOME:-$HOME/sam/dimos}"
export DIMOS_VENV="${DIMOS_VENV:-$HOME/dimos-env}"
source "$DIMOS_VENV/bin/activate"
cd "$DIMOS_HOME"
PYTHONPATH="$DIMOS_HOME/hackathon/pawtrack/src:$DIMOS_HOME" pytest -o addopts= \
hackathon/pawtrack/tests/test_identify.py \
hackathon/pawtrack/tests/test_greeter_state.py \
hackathon/pawtrack/tests/test_greeter_container.py \
hackathon/pawtrack/tests/test_occupancy.py
```
62 changes: 62 additions & 0 deletions hackathon/pawtrack/integration/greeter_agentic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""Version-controlled copy of the `greeter-agentic` `dimos run` blueprint.

The greeter dog: wander (DimOS patrol) until a person sitting on a chair is
found, pick a random not-yet-greeted one, walk over, circle to face them, and
wave hello -- then resume the patrol. The autonomous loop lives in
``GreeterSkillContainer``; start/stop it via MCP.

Install it next to the stock agentic blueprints in the DimOS source tree and
regenerate the registry:

cp integration/greeter_agentic.py \\
"$DIMOS_HOME/dimos/robot/unitree/go2/blueprints/agentic/"
pytest -o addopts="" \\
"$DIMOS_HOME/dimos/robot/test_all_blueprints_generation.py"

Then (with the `pawtrack` package importable):

PYTHONPATH=src PAWTRACK_MODEL=openai:deepseek-chat \
dimos run greeter-agentic --robot-ip <dog_ip>
dimos mcp call start_greeting # or tell the agent: "go greet people"
dimos mcp call stop_greeting # halt

This is the stock ``unitree-go2-agentic`` general agent **plus** the greeter
skill container -- i.e. a normal Go2 agent that can navigate, speak, run sport
commands, etc., and *also* knows how to greet. It uses the agent's default
general system prompt (no narrow greeter prompt); the agent discovers the
greeting from the skill docstrings (``start_greeting`` / ``stop_greeting`` /
``greeter_status`` / ``wave_hello``) and calls it when asked, like any other
skill. The wander/greet loop itself is autonomous once started. Model defaults
to the agent's default; override with ``PAWTRACK_MODEL``.
"""

from __future__ import annotations

import os

from dimos.agents.mcp.mcp_client import McpClient
from dimos.agents.mcp.mcp_server import McpServer
from dimos.core.coordination.blueprints import autoconnect
from dimos.robot.unitree.go2.blueprints.agentic._common_agentic import (
_common_agentic,
)
from dimos.robot.unitree.go2.blueprints.smart.unitree_go2_spatial import (
unitree_go2_spatial,
)

from pawtrack.greeter_container import GreeterSkillContainer

_MODEL = os.environ.get("PAWTRACK_MODEL")

# Stock unitree-go2-agentic (general agent, default prompt) + the greeter skill.
_agent = (
McpClient.blueprint(model=_MODEL) if _MODEL else McpClient.blueprint()
)

greeter_agentic = autoconnect(
unitree_go2_spatial,
McpServer.blueprint(),
_agent,
_common_agentic,
GreeterSkillContainer.blueprint(),
)
46 changes: 46 additions & 0 deletions hackathon/pawtrack/integration/pawtrack_agentic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""Version-controlled copy of the PawTrack `dimos run` blueprint.

`dimos run <name>` resolves names from a registry that the generator builds by
scanning only the dimos source tree, so the blueprint object has to live inside
that tree. This file is the canonical copy; install it with:

cp integration/pawtrack_agentic.py \\
"$DIMOS_HOME/dimos/robot/unitree/go2/blueprints/agentic/"
pytest "$DIMOS_HOME/dimos/robot/test_all_blueprints_generation.py" # regen

Then (with the `pawtrack` package importable):

PYTHONPATH=src dimos run pawtrack-agentic --robot-ip <dog_ip>

It rebuilds the four parts of the stock ``unitree-go2-agentic`` blueprint but
swaps in an ``McpClient`` with the PawTrack prompt and adds the PawTrack
subject-tracking skill container -- reusing the stock stack, no duplicate
agent.
"""

from __future__ import annotations

import os

from dimos.agents.mcp.mcp_client import McpClient
from dimos.agents.mcp.mcp_server import McpServer
from dimos.core.coordination.blueprints import autoconnect
from dimos.robot.unitree.go2.blueprints.agentic._common_agentic import (
_common_agentic,
)
from dimos.robot.unitree.go2.blueprints.smart.unitree_go2_spatial import (
unitree_go2_spatial,
)

from pawtrack.skill_container import PawTrackSkillContainer
from pawtrack.system_prompt import PAWTRACK_PROMPT

_MODEL = os.environ.get("PAWTRACK_MODEL", "openai:gpt-5.1")

pawtrack_agentic = autoconnect(
unitree_go2_spatial,
McpServer.blueprint(),
McpClient.blueprint(model=_MODEL, system_prompt=PAWTRACK_PROMPT),
_common_agentic,
PawTrackSkillContainer.blueprint(),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""PawTrack agentic blueprint with optional prebuilt-map relocalization.

Install this next to ``pawtrack_agentic.py`` in the DimOS source tree, then
regenerate ``all_blueprints``:

cp integration/pawtrack_agentic_relocalization.py \
"$DIMOS_HOME/dimos/robot/unitree/go2/blueprints/agentic/"
pytest -o addopts="" \
"$DIMOS_HOME/dimos/robot/test_all_blueprints_generation.py"

Run with a prebuilt map:

PYTHONPATH=src dimos run pawtrack-agentic-relocalization \
--robot-ip <dog_ip> \
-o relocalizationmodule.map_file=<premap_name>

This intentionally keeps the existing ``pawtrack-agentic`` blueprint
unchanged.
Use this blueprint only when you want ``subject_map_pose`` in addition to the
always-on ``subject_world_pose``.
"""

from __future__ import annotations

import os

from dimos.agents.mcp.mcp_client import McpClient
from dimos.agents.mcp.mcp_server import McpServer
from dimos.core.coordination.blueprints import autoconnect
from dimos.mapping.relocalization.module import RelocalizationModule
from dimos.robot.unitree.go2.blueprints.agentic._common_agentic import (
_common_agentic,
)
from dimos.robot.unitree.go2.blueprints.smart.unitree_go2_spatial import (
unitree_go2_spatial,
)

from pawtrack.skill_container import PawTrackSkillContainer
from pawtrack.system_prompt import PAWTRACK_PROMPT

_MODEL = os.environ.get("PAWTRACK_MODEL", "openai:gpt-5.1")

pawtrack_agentic_relocalization = autoconnect(
unitree_go2_spatial,
RelocalizationModule.blueprint(),
McpServer.blueprint(),
McpClient.blueprint(model=_MODEL, system_prompt=PAWTRACK_PROMPT),
_common_agentic,
PawTrackSkillContainer.blueprint(),
)
19 changes: 19 additions & 0 deletions hackathon/pawtrack/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[build-system]
requires = ["setuptools>=70", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "pawtrack"
version = "0.1.0"
description = "PawTrack: a Unitree Go2 that finds and tracks a described subject."
requires-python = ">=3.10"
dependencies = []

[tool.setuptools.packages.find]
where = ["src"]

[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]
addopts = "-q"

Loading