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
42 changes: 42 additions & 0 deletions .github/workflows/test-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ inputs.ref }}
# Need history so we can diff the changed paths against the base.
fetch-depth: 0
persist-credentials: false

- name: Set up Python
Expand All @@ -31,6 +33,46 @@ jobs:
sudo apt-get update
sudo apt-get install -y libosmesa6-dev ffmpeg

# The Device Connect integration (strands_robots/device_connect) can
# depend on changes in the device-connect-edge / agent-tools packages
# that are not yet on PyPI. When this PR touches the integration, install
# those packages from source (DEVICE_CONNECT_SOURCE_REF) so CI exercises
# the matching version instead of the published one.
- name: Detect Device Connect integration changes
id: dc_changed
run: |
BASE="origin/${{ github.base_ref || 'main' }}"
git fetch origin "${{ github.base_ref || 'main' }}" --depth=1 || true
if git diff --name-only "$BASE"...HEAD 2>/dev/null | grep -q '^strands_robots/device_connect/'; then
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "Device Connect integration changed -> will install device-connect from source"
else
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "No Device Connect integration changes -> using published device-connect-edge"
fi

- name: Pin device-connect to source (integration changed)
if: steps.dc_changed.outputs.changed == 'true'
env:
# Source of truth for the device-connect packages while the
# corresponding device-connect PR is unreleased. Update the ref (or
# repo) here to point at the branch/tag that carries the matching
# changes; revert to the published wheel once it ships to PyPI.
DEVICE_CONNECT_REPO: ${{ vars.DEVICE_CONNECT_REPO || 'arm/device-connect' }}
DEVICE_CONNECT_SOURCE_REF: ${{ vars.DEVICE_CONNECT_SOURCE_REF || 'main' }}
run: |
# The hatch test env is an ISOLATED uv venv, so an outer `pip install`
# would not reach it. Instead we write a uv override file: uv MERGES
# UV_OVERRIDE entries with the pyproject [tool.uv] override-dependencies
# (torch pins), so this redirects ONLY the device-connect packages to
# source without disturbing anything else.
cat > "${GITHUB_WORKSPACE}/dc-source-override.txt" <<EOF
device-connect-edge @ git+https://github.com/${DEVICE_CONNECT_REPO}.git@${DEVICE_CONNECT_SOURCE_REF}#subdirectory=packages/device-connect-edge
device-connect-agent-tools @ git+https://github.com/${DEVICE_CONNECT_REPO}.git@${DEVICE_CONNECT_SOURCE_REF}#subdirectory=packages/device-connect-agent-tools
EOF
echo "UV_OVERRIDE=${GITHUB_WORKSPACE}/dc-source-override.txt" >> "$GITHUB_ENV"
echo "Pinned device-connect packages to ${DEVICE_CONNECT_REPO}@${DEVICE_CONNECT_SOURCE_REF}"

- name: Install dependencies
env:
UV_TORCH_BACKEND: cpu
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ extras you need:
| `groot-service` | pyzmq, msgpack | NVIDIA GR00T inference client |
| `mesh` | eclipse-zenoh, json5 | Peer-to-peer robot mesh |
| `mesh-iot` | awsiotsdk, awscrt, boto3 | AWS IoT Core mesh transport for fleets |
| `device-connect` | device-connect-edge, device-connect-agent-tools | Device-aware networking — discovery, RPC, events, safety (falls back to the built-in mesh if absent) |
| `benchmark-libero` | libero | LIBERO benchmark evaluation |
| `all` | everything above | Kitchen sink |

Expand Down
8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,20 @@ mesh-iot = [
"awscrt>=0.20.0,<1.0.0",
"boto3>=1.34.0,<2.0.0",
]
# Device Connect — device-aware networking layer (discovery, RPC, events,
# safety). The primary transport in server mode; when this extra is not
# installed, robot_mesh() falls back to the built-in Zenoh mesh.
device-connect = [
"device-connect-edge>=0.2.0",
"device-connect-agent-tools>=0.1.0",
]
all = [
"strands-robots[groot-service]",
"strands-robots[lerobot]",
"strands-robots[sim-mujoco]",
"strands-robots[mesh]",
"strands-robots[mesh-iot]",
"strands-robots[device-connect]",
]
dev = [
"pytest>=6.0,<9.0.0",
Expand Down
22 changes: 22 additions & 0 deletions strands_robots/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
# the lazy attributes below (the runtime __getattr__ resolves them to Any
# from the static analyzer's perspective). PEP 562.
if TYPE_CHECKING:
from strands_robots.device_connect import (
ReachyMiniDriver,
RobotDeviceDriver,
SimulationDeviceDriver,
init_device_connect,
init_device_connect_sync,
)
from strands_robots.policies.groot import Gr00tPolicy
from strands_robots.registry import list_robots
from strands_robots.robot import Robot
Expand All @@ -48,6 +55,7 @@
from strands_robots.tools.lerobot_camera import lerobot_camera
from strands_robots.tools.lerobot_teleoperate import lerobot_teleoperate
from strands_robots.tools.pose_tool import pose_tool
from strands_robots.tools.robot_mesh import robot_mesh
from strands_robots.tools.serial_tool import serial_tool

# ------------------------------------------------------------------
Expand Down Expand Up @@ -81,6 +89,14 @@
"lerobot_teleoperate": ("strands_robots.tools.lerobot_teleoperate", "lerobot_teleoperate"),
"pose_tool": ("strands_robots.tools.pose_tool", "pose_tool"),
"serial_tool": ("strands_robots.tools.serial_tool", "serial_tool"),
# Robot mesh coordination tool (Device Connect dispatch + mesh fallback)
"robot_mesh": ("strands_robots.tools.robot_mesh", "robot_mesh"),
# Device Connect integration — wraps robots as Device Connect devices
"init_device_connect": ("strands_robots.device_connect", "init_device_connect"),
"init_device_connect_sync": ("strands_robots.device_connect", "init_device_connect_sync"),
"RobotDeviceDriver": ("strands_robots.device_connect", "RobotDeviceDriver"),
"SimulationDeviceDriver": ("strands_robots.device_connect", "SimulationDeviceDriver"),
"ReachyMiniDriver": ("strands_robots.device_connect", "ReachyMiniDriver"),
}

__all__ = [
Expand All @@ -106,6 +122,12 @@
"lerobot_calibrate",
"serial_tool",
"pose_tool",
"robot_mesh",
"init_device_connect",
"init_device_connect_sync",
"RobotDeviceDriver",
"SimulationDeviceDriver",
"ReachyMiniDriver",
]


Expand Down
Loading