LangSmith observability for LLM and robot SDKs
Project description
ShadowDance
One line. Full LangSmith observability for LLM and robot SDKs.
from shadowdance import ShadowDance
# OpenAI client
client = OpenAI()
client = ShadowDance(client) # <- ONE LINE
response = client.chat.completions.create(...) # <- traced!
# Robot client
client = SportClient()
client = ShadowDance(client) # <- ONE LINE
client.Move(0.3, 0, 0) # <- traced!
Every call is now a traced LangSmith event.
What it does
ShadowDance() wraps any client object (OpenAI, Unitree, etc.). It intercepts every method call and logs it as a LangSmith run — command name, arguments, result, timestamp, duration. No code changes beyond the one-liner.
If the client is being called from inside a LangChain agent, the traces nest automatically under the agent's run tree.
How LLM Robot Systems Work
Modern LLM-powered robots use a layered architecture:
┌─────────────────────────────────────────┐
│ High-Level Agent (ShadowDance here!) │
│ "pick up the box" → coordinates layers │
├─────────────────────────────────────────┤
│ Task Planning (LLM) │
│ Natural language → symbolic plan │
├─────────────────────────────────────────┤
│ Perception (VLM) │
│ Camera image → object positions │
├─────────────────────────────────────────┤
│ Low-Level Control │
│ Trajectories → motor commands │
└─────────────────────────────────────────┘
ShadowDance traces the full stack so you can debug:
- What did the LLM plan?
- What did the VLM see?
- What commands were sent?
- Where did it fail?
Installation
pip install -e .
# or
pip install langsmith
Setup
# Install dependencies
pip install -e .
# Load environment variables
source .env
Configuration
The .env file contains:
# LangSmith tracing
LANGCHAIN_API_KEY=...
LANGCHAIN_TRACING_V2=true
LANGCHAIN_PROJECT=shadowdance
# OpenRouter (OpenAI-compatible API)
OPENAI_API_KEY=...
OPENAI_BASE_URL=https://openrouter.ai/api/v1
# Default model for vision and planning
DEFAULT_MODEL=openrouter/hunter-alpha
Using Different Models
Change DEFAULT_MODEL in .env to use different models:
- Vision + Text:
openrouter/hunter-alpha(multimodal) - Free models: See OpenRouter's model list
Test Connection
python examples/test_openrouter.py
Quick Start
With a Real Robot
from unitree_sdk2py.go2.sport.sport_client import SportClient
from shadowdance import ShadowDance
client = SportClient()
client.Init()
# Wrap with ShadowDance
client = ShadowDance(client)
# All calls are now traced
client.Move(0.3, 0, 0)
With Virtual Robot (No Hardware Required)
Test LangSmith tracing without a physical robot:
source .env
python examples/with_virtual_robot.py
This runs a simulated robot that responds to commands just like a real Unitree robot. Perfect for development and testing!
Examples
Quick Start: OpenAI Client
from openai import OpenAI
from shadowdance import ShadowDance
client = OpenAI()
client = ShadowDance(client) # ONE LINE
response = client.chat.completions.create(
model="openrouter/hunter-alpha",
messages=[{"role": "user", "content": "Hello!"}],
)
Run: python examples/openai_client.py
Code-as-Policies (Full Demo)
Modern LLM robot architecture: VLM → LLM → Code → Robot
python examples/code_as_policies.py
This demonstrates the Code-as-Policies approach:
- VLM analyzes image → detects white box at [0.0, 0.1, 0.72]
- LLM generates Python code →
robot.move_to(...),robot.close_gripper(...) - Safe executor runs code → robot picks up box
- ShadowDance traces everything → debug in LangSmith
Task: "Pick up the white box"
↓
Vision: white_box detected at [0.0, 0.1, 0.72]
↓
LLM: Generates 4-line Python program
↓
Robot: move_to → close_gripper → move_to (SUCCESS)
Example output in LangSmith
Run: robot_session
└── Move(vx=0.3, vy=0, vyaw=0) 12ms ✓
└── StandUp() 8ms ✓
└── Move(vx=0, vy=0.3, vyaw=0) 11ms ✓
└── Damp() 9ms ✓
View your traces at smith.langchain.com
Testing
# Run unit tests
python test_shadowdance.py
# Run with virtual robot
python examples/with_virtual_robot.py
API
ShadowDance(client)
Wraps a client object with LangSmith tracing.
Args:
client: The Unitree SDK client object to wrap
Returns:
- A proxy object that intercepts all method calls
Example:
wrapped = ShadowDance(client)
wrapped.Move(0.3, 0, 0) # Traced as "Move" in LangSmith
File structure
./shadowdance.py # Main implementation
./test_shadowdance.py # Unit tests
./examples/
├── basic.py # Basic usage
├── error_handling.py # Error handling demo
├── virtual_robot.py # Virtual robot server
└── with_virtual_robot.py # Virtual robot + LangSmith demo
./pyproject.toml # Package configuration
./requirements.txt # Dependencies
./.env # LangSmith credentials (gitignored)
Why
The Unitree SDK has no logging, no observability, no way to know why your robot did what it did. LangSmith fixes that. This wrapper connects them with one line of code.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file shadowdance-0.1.0.tar.gz.
File metadata
- Download URL: shadowdance-0.1.0.tar.gz
- Upload date:
- Size: 29.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1d32347b5bcc51b04cd893431a84456462d6daedb74a88fbdde8e80a89dbfe1
|
|
| MD5 |
a7c6012b7d995f8180957184027c129c
|
|
| BLAKE2b-256 |
a2eda9e7a446954453bf59f163d09cf0782b2746f89483d2567db809e44d8bc5
|
File details
Details for the file shadowdance-0.1.0-py3-none-any.whl.
File metadata
- Download URL: shadowdance-0.1.0-py3-none-any.whl
- Upload date:
- Size: 5.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba7731981d3531dbb4df01709494b9b7e1d7d76177238e3145dbba0d1d001d42
|
|
| MD5 |
6137c3d2e51b0b71be99426600814356
|
|
| BLAKE2b-256 |
087bc62cfe8b61981c3013e596e0b81761bd6c63a9ecc46157a1e8a003ea99eb
|