menlo-robot-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ .venv/
2
+ .pytest_cache/
3
+ .mypy_cache/
4
+ .ruff_cache/
5
+ .regen-check/
6
+ *.egg-info/
7
+ dist/
8
+ build/
@@ -0,0 +1,179 @@
1
+ Metadata-Version: 2.4
2
+ Name: menlo-robot-sdk
3
+ Version: 0.1.0
4
+ Summary: Python client for the Menlo Robot Control Service (RCS) control plane.
5
+ License: MIT
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: httpx<1,>=0.28
8
+ Requires-Dist: pydantic<3,>=2.9
9
+ Provides-Extra: livekit
10
+ Requires-Dist: livekit<1,>=0.18; extra == 'livekit'
11
+ Provides-Extra: menlo-rcs-types
12
+ Requires-Dist: menlo-rcs-types; extra == 'menlo-rcs-types'
13
+ Description-Content-Type: text/markdown
14
+
15
+ # menlo-robot-sdk
16
+
17
+ Python client for the [Robot Control Service (RCS)](../../../services/rcs) control plane: robot CRUD and LiveKit session lifecycle.
18
+
19
+ > **⚠️ Alpha — Not for Production Use**
20
+ >
21
+ > This package is in active development and may have breaking changes between minor versions.
22
+ > APIs are subject to change. Use at your own risk.
23
+
24
+ > **Roadmap** — Stage 0 (control plane) is shipped; Stages 1–5 cover production hardening, command/telemetry API, identity, publishing, and observability. No fixed dates — see [docs/ROADMAP.md](./docs/ROADMAP.md) and [issue #125](https://github.com/menloresearch/mono/issues/125).
25
+ >
26
+ > **Rough product spec** (connect, skills, runtime helpers): [ADR 0002](./docs/adr/0002-menlo-robot-sdk-rough-product-spec.md) — what works today vs blocked on RCS ([#136](https://github.com/menloresearch/mono/issues/136)).
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ uv add menlo-robot-sdk
32
+
33
+ # With LiveKit support
34
+ uv add "menlo-robot-sdk[livekit]"
35
+ ```
36
+
37
+ ```bash
38
+ cd packages/py/menlo-robot-sdk
39
+ uv sync --all-extras --dev
40
+ uv run python -c "from menlo_robot_sdk import AsyncClient; print('ok')"
41
+ ```
42
+
43
+ Path dependency from another uv project:
44
+
45
+ ```toml
46
+ [tool.uv.sources]
47
+ menlo-robot-sdk = { path = "../../packages/py/menlo-robot-sdk", editable = true }
48
+ ```
49
+
50
+ When PyPI publishing lands (ROADMAP Stage 4): `uv add menlo-robot-sdk` and `uv add "menlo-robot-sdk[livekit]"`.
51
+
52
+ ## Configuration
53
+
54
+ See [`.env.example`](./.env.example) for all client env vars (placeholders only — no secrets).
55
+
56
+ | Variable | Description |
57
+ |----------|-------------|
58
+ | `MENLO_RCS_URL` | RCS base URL (e.g. `http://localhost:8002`) |
59
+ | `MENLO_IDENTITY` | Full `X-Menlo-Identity` header value (JWS or unsigned JSON) |
60
+ | `MENLO_IDENTITY_FILE` | Path to file containing identity (overrides `MENLO_IDENTITY`) |
61
+ | `MENLO_ROBOT_SDK_TIMEOUT` | Per-request timeout in seconds (default `30`) |
62
+ | `MENLO_ROBOT_SDK_MAX_RETRIES` | Max retries on transport errors / safe HTTP codes (default `2`) |
63
+ | `MENLO_ROBOT_SDK_DEBUG` | Set to `1` to log httpx request/response events |
64
+ | `MENLO_LIVEKIT_URL` | Optional override for `connect_session()` when RCS returns an internal hostname |
65
+ | `MENLO_RCS_INTEGRATION` | Set to `1` to run integration tests (see [MANUAL_TESTING.md](./MANUAL_TESTING.md)) |
66
+
67
+ `MENLO_API_KEY` alone is **not** supported for RCS; use `MENLO_IDENTITY` until token exchange ships ([#136](https://github.com/menloresearch/mono/issues/136)). Rough-spec **url** = `MENLO_RCS_URL` / `MenloSettings.url`.
68
+
69
+ Pass `MenloSettings` or omit `rcs_url` / `identity` on `Client` / `AsyncClient` to load from env. If you pass `rcs_url` and `identity` explicitly, you must pass **both**; passing only one raises `ValueError`. Optional `timeout` / `max_retries` override env defaults when using the env path.
70
+
71
+ `robots.update(robot_id, name=...)` sends only the keyword arguments you provide (omitted fields are not sent as `null`).
72
+
73
+ ```python
74
+ from menlo_robot_sdk import AsyncClient, DevIdentity, MenloSettings, workers
75
+
76
+ settings = MenloSettings.from_env()
77
+ # or local unsigned JSON:
78
+ settings = MenloSettings(
79
+ rcs_url="http://localhost:8002",
80
+ identity=DevIdentity(sub="user_dev", organization_id="org_dev", team_id="team_dev").to_header(),
81
+ )
82
+
83
+ async with AsyncClient(settings=settings) as client:
84
+ created = await client.robots.create(name="Lab bot", model="asimov-v0")
85
+ print(created.pin_code) # show-once PIN — save securely
86
+
87
+ page = await client.robots.list(limit=20)
88
+ async for robot in client.robots.iter(limit=50):
89
+ print(robot.id)
90
+
91
+ session = await client.robots.create_session(
92
+ created.robot.id,
93
+ workers=workers.for_rcs_stack(),
94
+ )
95
+ ```
96
+
97
+ ## LiveKit (optional)
98
+
99
+ ```python
100
+ from menlo_robot_sdk.livekit import connect_session
101
+
102
+ room = await connect_session(session) # uses session.livekit_url
103
+ # room = await connect_session(session, livekit_url=<URL reachable from your host>) # override for Docker
104
+ ```
105
+
106
+ In a sync-only script (no running event loop), use ``asyncio.run(connect_session(session))``.
107
+
108
+ ## Connect helper (rough spec — partial)
109
+
110
+ ```python
111
+ from menlo_robot_sdk import AsyncClient, ConnectCallbacks, connect, workers
112
+
113
+ async with AsyncClient() as client:
114
+ handle = await connect(
115
+ client,
116
+ "rb_myrobot",
117
+ workers=workers.for_rcs_stack(),
118
+ join_livekit=False, # default True needs menlo-robot-sdk[livekit] for LiveKit + callbacks
119
+ )
120
+ # handle.get_robot_status(), invoke(), … raise MenloNotAvailableError until mono#136
121
+ await handle.disconnect()
122
+ ```
123
+
124
+ See [ADR 0002](./docs/adr/0002-menlo-robot-sdk-rough-product-spec.md) for the full matrix.
125
+
126
+ ## Errors and retries
127
+
128
+ RCS errors use `{ "code", "message", "details" }`. The SDK raises `MenloAPIError` for HTTP status ≥ 400. Retries (default 2) apply to transport failures and **429** on safe methods; **POST /v1/robots** and **POST …/session** are not retried. Backoff is capped at **30s**. See [ADR 0001](./docs/adr/0001-menlo-robot-sdk-v1-rcs-control-plane.md).
129
+
130
+ ## Examples
131
+
132
+ Runnable cookbooks (one use case per file, flat snippets): [examples/README.md](./examples/README.md). Run after local `rcs-stack` — see [MANUAL_TESTING.md](./MANUAL_TESTING.md).
133
+
134
+ ## Testing
135
+
136
+ - **Unit** (mocked HTTP): `uv run pytest -q` (integration excluded by default)
137
+ - **Integration** (live RCS): see [MANUAL_TESTING.md](./MANUAL_TESTING.md)
138
+ - **QA checklist** (PR / release): [MANUAL_TESTING.md § QA checklist](./MANUAL_TESTING.md#qa-checklist)
139
+
140
+ ## Development
141
+
142
+ ```bash
143
+ cd packages/py/menlo-robot-sdk
144
+ uv sync --all-extras --dev
145
+ cd ../../../services/rcs && uv sync --frozen --no-dev && cd ../../packages/py/menlo-robot-sdk
146
+ uv run python scripts/export_rcs_openapi.py
147
+ uv run python scripts/regen_models.py --check
148
+ uv run ruff check .
149
+ uv run mypy src
150
+ uv run pytest -q
151
+ export MENLO_RCS_INTEGRATION=1
152
+ uv run pytest tests/integration -m integration -q # live RCS; see MANUAL_TESTING.md
153
+ ```
154
+
155
+ ## Publishing
156
+
157
+ This package is published to PyPI via GitHub Actions on version tags. No API token needed — uses PyPI Trusted Publishing (OIDC).
158
+
159
+ **To release a new version:**
160
+
161
+ ```bash
162
+ # 1. Bump version in pyproject.toml
163
+ cd packages/py/menlo-robot-sdk
164
+ # Edit version in pyproject.toml, then:
165
+ uv lock
166
+
167
+ # 2. Commit and merge to main
168
+ git add pyproject.toml uv.lock
169
+ git commit -m "chore: bump menlo-robot-sdk to v0.5.0"
170
+ # ... push PR, get approval, merge
171
+
172
+ # 3. Create and push the version tag (triggers publish workflow)
173
+ git checkout main && git pull
174
+ git tag menlo-robot-sdk-v0.5.0
175
+ git push origin menlo-robot-sdk-v0.5.0
176
+ ```
177
+
178
+ The workflow `.github/workflows/menlo-robot-sdk-publish.yml` builds and publishes automatically. Check the Actions tab for status.
179
+ ```
@@ -0,0 +1,165 @@
1
+ # menlo-robot-sdk
2
+
3
+ Python client for the [Robot Control Service (RCS)](../../../services/rcs) control plane: robot CRUD and LiveKit session lifecycle.
4
+
5
+ > **⚠️ Alpha — Not for Production Use**
6
+ >
7
+ > This package is in active development and may have breaking changes between minor versions.
8
+ > APIs are subject to change. Use at your own risk.
9
+
10
+ > **Roadmap** — Stage 0 (control plane) is shipped; Stages 1–5 cover production hardening, command/telemetry API, identity, publishing, and observability. No fixed dates — see [docs/ROADMAP.md](./docs/ROADMAP.md) and [issue #125](https://github.com/menloresearch/mono/issues/125).
11
+ >
12
+ > **Rough product spec** (connect, skills, runtime helpers): [ADR 0002](./docs/adr/0002-menlo-robot-sdk-rough-product-spec.md) — what works today vs blocked on RCS ([#136](https://github.com/menloresearch/mono/issues/136)).
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ uv add menlo-robot-sdk
18
+
19
+ # With LiveKit support
20
+ uv add "menlo-robot-sdk[livekit]"
21
+ ```
22
+
23
+ ```bash
24
+ cd packages/py/menlo-robot-sdk
25
+ uv sync --all-extras --dev
26
+ uv run python -c "from menlo_robot_sdk import AsyncClient; print('ok')"
27
+ ```
28
+
29
+ Path dependency from another uv project:
30
+
31
+ ```toml
32
+ [tool.uv.sources]
33
+ menlo-robot-sdk = { path = "../../packages/py/menlo-robot-sdk", editable = true }
34
+ ```
35
+
36
+ When PyPI publishing lands (ROADMAP Stage 4): `uv add menlo-robot-sdk` and `uv add "menlo-robot-sdk[livekit]"`.
37
+
38
+ ## Configuration
39
+
40
+ See [`.env.example`](./.env.example) for all client env vars (placeholders only — no secrets).
41
+
42
+ | Variable | Description |
43
+ |----------|-------------|
44
+ | `MENLO_RCS_URL` | RCS base URL (e.g. `http://localhost:8002`) |
45
+ | `MENLO_IDENTITY` | Full `X-Menlo-Identity` header value (JWS or unsigned JSON) |
46
+ | `MENLO_IDENTITY_FILE` | Path to file containing identity (overrides `MENLO_IDENTITY`) |
47
+ | `MENLO_ROBOT_SDK_TIMEOUT` | Per-request timeout in seconds (default `30`) |
48
+ | `MENLO_ROBOT_SDK_MAX_RETRIES` | Max retries on transport errors / safe HTTP codes (default `2`) |
49
+ | `MENLO_ROBOT_SDK_DEBUG` | Set to `1` to log httpx request/response events |
50
+ | `MENLO_LIVEKIT_URL` | Optional override for `connect_session()` when RCS returns an internal hostname |
51
+ | `MENLO_RCS_INTEGRATION` | Set to `1` to run integration tests (see [MANUAL_TESTING.md](./MANUAL_TESTING.md)) |
52
+
53
+ `MENLO_API_KEY` alone is **not** supported for RCS; use `MENLO_IDENTITY` until token exchange ships ([#136](https://github.com/menloresearch/mono/issues/136)). Rough-spec **url** = `MENLO_RCS_URL` / `MenloSettings.url`.
54
+
55
+ Pass `MenloSettings` or omit `rcs_url` / `identity` on `Client` / `AsyncClient` to load from env. If you pass `rcs_url` and `identity` explicitly, you must pass **both**; passing only one raises `ValueError`. Optional `timeout` / `max_retries` override env defaults when using the env path.
56
+
57
+ `robots.update(robot_id, name=...)` sends only the keyword arguments you provide (omitted fields are not sent as `null`).
58
+
59
+ ```python
60
+ from menlo_robot_sdk import AsyncClient, DevIdentity, MenloSettings, workers
61
+
62
+ settings = MenloSettings.from_env()
63
+ # or local unsigned JSON:
64
+ settings = MenloSettings(
65
+ rcs_url="http://localhost:8002",
66
+ identity=DevIdentity(sub="user_dev", organization_id="org_dev", team_id="team_dev").to_header(),
67
+ )
68
+
69
+ async with AsyncClient(settings=settings) as client:
70
+ created = await client.robots.create(name="Lab bot", model="asimov-v0")
71
+ print(created.pin_code) # show-once PIN — save securely
72
+
73
+ page = await client.robots.list(limit=20)
74
+ async for robot in client.robots.iter(limit=50):
75
+ print(robot.id)
76
+
77
+ session = await client.robots.create_session(
78
+ created.robot.id,
79
+ workers=workers.for_rcs_stack(),
80
+ )
81
+ ```
82
+
83
+ ## LiveKit (optional)
84
+
85
+ ```python
86
+ from menlo_robot_sdk.livekit import connect_session
87
+
88
+ room = await connect_session(session) # uses session.livekit_url
89
+ # room = await connect_session(session, livekit_url=<URL reachable from your host>) # override for Docker
90
+ ```
91
+
92
+ In a sync-only script (no running event loop), use ``asyncio.run(connect_session(session))``.
93
+
94
+ ## Connect helper (rough spec — partial)
95
+
96
+ ```python
97
+ from menlo_robot_sdk import AsyncClient, ConnectCallbacks, connect, workers
98
+
99
+ async with AsyncClient() as client:
100
+ handle = await connect(
101
+ client,
102
+ "rb_myrobot",
103
+ workers=workers.for_rcs_stack(),
104
+ join_livekit=False, # default True needs menlo-robot-sdk[livekit] for LiveKit + callbacks
105
+ )
106
+ # handle.get_robot_status(), invoke(), … raise MenloNotAvailableError until mono#136
107
+ await handle.disconnect()
108
+ ```
109
+
110
+ See [ADR 0002](./docs/adr/0002-menlo-robot-sdk-rough-product-spec.md) for the full matrix.
111
+
112
+ ## Errors and retries
113
+
114
+ RCS errors use `{ "code", "message", "details" }`. The SDK raises `MenloAPIError` for HTTP status ≥ 400. Retries (default 2) apply to transport failures and **429** on safe methods; **POST /v1/robots** and **POST …/session** are not retried. Backoff is capped at **30s**. See [ADR 0001](./docs/adr/0001-menlo-robot-sdk-v1-rcs-control-plane.md).
115
+
116
+ ## Examples
117
+
118
+ Runnable cookbooks (one use case per file, flat snippets): [examples/README.md](./examples/README.md). Run after local `rcs-stack` — see [MANUAL_TESTING.md](./MANUAL_TESTING.md).
119
+
120
+ ## Testing
121
+
122
+ - **Unit** (mocked HTTP): `uv run pytest -q` (integration excluded by default)
123
+ - **Integration** (live RCS): see [MANUAL_TESTING.md](./MANUAL_TESTING.md)
124
+ - **QA checklist** (PR / release): [MANUAL_TESTING.md § QA checklist](./MANUAL_TESTING.md#qa-checklist)
125
+
126
+ ## Development
127
+
128
+ ```bash
129
+ cd packages/py/menlo-robot-sdk
130
+ uv sync --all-extras --dev
131
+ cd ../../../services/rcs && uv sync --frozen --no-dev && cd ../../packages/py/menlo-robot-sdk
132
+ uv run python scripts/export_rcs_openapi.py
133
+ uv run python scripts/regen_models.py --check
134
+ uv run ruff check .
135
+ uv run mypy src
136
+ uv run pytest -q
137
+ export MENLO_RCS_INTEGRATION=1
138
+ uv run pytest tests/integration -m integration -q # live RCS; see MANUAL_TESTING.md
139
+ ```
140
+
141
+ ## Publishing
142
+
143
+ This package is published to PyPI via GitHub Actions on version tags. No API token needed — uses PyPI Trusted Publishing (OIDC).
144
+
145
+ **To release a new version:**
146
+
147
+ ```bash
148
+ # 1. Bump version in pyproject.toml
149
+ cd packages/py/menlo-robot-sdk
150
+ # Edit version in pyproject.toml, then:
151
+ uv lock
152
+
153
+ # 2. Commit and merge to main
154
+ git add pyproject.toml uv.lock
155
+ git commit -m "chore: bump menlo-robot-sdk to v0.5.0"
156
+ # ... push PR, get approval, merge
157
+
158
+ # 3. Create and push the version tag (triggers publish workflow)
159
+ git checkout main && git pull
160
+ git tag menlo-robot-sdk-v0.5.0
161
+ git push origin menlo-robot-sdk-v0.5.0
162
+ ```
163
+
164
+ The workflow `.github/workflows/menlo-robot-sdk-publish.yml` builds and publishes automatically. Check the Actions tab for status.
165
+ ```