grid-cortex-client 0.6.0__tar.gz → 0.6.1__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.
Files changed (65) hide show
  1. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/CLAUDE.md +2 -2
  2. grid_cortex_client-0.6.1/MIGRATION.md +19 -0
  3. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/PKG-INFO +1 -1
  4. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/pyproject.toml +1 -0
  5. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/client.py +3 -4
  6. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/cortex_hub_client.py +3 -3
  7. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/pi05.py +26 -0
  8. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_c_radio.py +2 -2
  9. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_contact_graspnet.py +2 -2
  10. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_cortex_hub_client.py +14 -12
  11. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_da3metric.py +2 -2
  12. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_fast_foundation_stereo.py +2 -2
  13. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_foundation_stereo.py +2 -2
  14. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_graspgen.py +2 -2
  15. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_graspgenx.py +2 -2
  16. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_gsam2.py +2 -2
  17. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_locate_anything.py +2 -2
  18. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_metric3d.py +2 -2
  19. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_moondream.py +2 -2
  20. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_oneformer.py +2 -2
  21. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_owlv2.py +2 -2
  22. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_pi05.py +2 -2
  23. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_qwen_vl.py +2 -2
  24. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_sam2.py +2 -2
  25. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_sam3.py +2 -2
  26. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_ur5e_pyroki_collision_batch.py +2 -2
  27. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_ur5e_pyroki_fk.py +2 -2
  28. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_zoedepth.py +2 -2
  29. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/.gitignore +0 -0
  30. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/README.md +0 -0
  31. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/__init__.py +0 -0
  32. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/cortex_client.py +0 -0
  33. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/model_type.py +0 -0
  34. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/__init__.py +0 -0
  35. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/base_model.py +0 -0
  36. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/c_radio.py +0 -0
  37. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/contact_graspnet.py +0 -0
  38. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/da3metric.py +0 -0
  39. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/fast_foundation_stereo.py +0 -0
  40. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/finetune_pi05.py +0 -0
  41. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/foundation_stereo.py +0 -0
  42. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/graspgen.py +0 -0
  43. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/graspgenx.py +0 -0
  44. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/gsam2.py +0 -0
  45. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/locate_anything.py +0 -0
  46. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/metric3d.py +0 -0
  47. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/moondream.py +0 -0
  48. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/oneformer.py +0 -0
  49. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/owlv2.py +0 -0
  50. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/qwen_vl.py +0 -0
  51. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/sam2.py +0 -0
  52. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/sam3.py +0 -0
  53. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/ur5e_pyroki_collision_batch.py +0 -0
  54. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/ur5e_pyroki_fk.py +0 -0
  55. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/models/zoedepth.py +0 -0
  56. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/preprocessing.py +0 -0
  57. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/tools/__init__.py +0 -0
  58. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/tools/generate_enum.py +0 -0
  59. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/tools/registry.py +0 -0
  60. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/utils.py +0 -0
  61. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/src/grid_cortex_client/ws.py +0 -0
  62. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/README.md +0 -0
  63. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/__init__.py +0 -0
  64. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/conftest.py +0 -0
  65. {grid_cortex_client-0.6.0 → grid_cortex_client-0.6.1}/tests/test_finetune_pi05.py +0 -0
@@ -5,7 +5,7 @@ Python client for the Cortex ML inference API. Published to **public PyPI**.
5
5
  ## Build & Test
6
6
 
7
7
  ```bash
8
- uv run --package grid-cortex-client pytest
8
+ BUILD_VERSION=0.0.0.dev0 uv run --project cortex --package grid-cortex-client pytest
9
9
  ```
10
10
 
11
11
  - Build tool: hatchling + hatch-vcs
@@ -27,7 +27,7 @@ uv run --package grid-cortex-client pytest
27
27
  | Stage | `https://cortex-stage.generalrobotics.dev/cortex` | `wss://cortex-stage.generalrobotics.dev/cortex/ws/ws` |
28
28
  | Prod | `https://cortex-prod.generalrobotics.dev/cortex` | `wss://cortex-prod.generalrobotics.dev/cortex/ws/ws` |
29
29
 
30
- Override via `GRID_CORTEX_BASE_URL` (REST) and `GRID_CORTEX_WS_URL` (WebSocket). Default is prod.
30
+ Override the REST/WebSocket base via `GRID_CORTEX_BASE_URL`. Default is prod.
31
31
 
32
32
  ## Publishing
33
33
 
@@ -0,0 +1,19 @@
1
+ # grid-cortex-client migration notes
2
+
3
+ ## `CORTEX_API_KEY` → `GRID_CORTEX_API_KEY` (breaking)
4
+
5
+ The client now resolves the API key from **`GRID_CORTEX_API_KEY`** only. The
6
+ legacy `CORTEX_API_KEY` environment-variable fallback in `CortexHubClient` has
7
+ been removed.
8
+
9
+ **Action required:** set `GRID_CORTEX_API_KEY` instead of `CORTEX_API_KEY`, or
10
+ pass `api_key=` explicitly to the client. Code that still relies on
11
+ `CORTEX_API_KEY` will construct the client with no key and get a `401` on the
12
+ first call.
13
+
14
+ This is a breaking change to the published package and must ship under a MAJOR
15
+ bump (`cortex-client/vX.0.0`) — see `client-versioning.md` (the squash subject
16
+ needs `feat(cortex-client)!:` or a `BREAKING CHANGE:` footer, or cut the MAJOR
17
+ manually). `GRID_CORTEX_API_KEY` is the single canonical name repo-wide: the
18
+ legacy `CORTEX_API_KEY` is no longer injected into the session pod either, so
19
+ customer skills that read `CORTEX_API_KEY` directly must migrate too.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: grid-cortex-client
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: Python client for Grid Cortex
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: Programming Language :: Python :: 3.8
@@ -53,4 +53,5 @@ markers = [
53
53
  [dependency-groups]
54
54
  dev = [
55
55
  "pytest>=8.3.5",
56
+ "pytest-asyncio>=0.24",
56
57
  ]
@@ -4,7 +4,7 @@ import httpx
4
4
  import logging
5
5
  from . import utils as _u
6
6
 
7
- BASE_URL = os.getenv("GRID_CORTEX_BASE_URL", "https://cortex-prod.generalrobotics.dev/cortex")
7
+ DEFAULT_BASE_URL = "https://cortex-prod.generalrobotics.dev/cortex"
8
8
 
9
9
  # Remove basicConfig, as library logging should not configure root logger
10
10
  # logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
@@ -51,7 +51,7 @@ class HTTPClient:
51
51
  headers["x-api-key"] = api_key
52
52
 
53
53
  # Determine the final base URL
54
- final_base_url = base_url or os.getenv("GRID_CORTEX_BASE_URL", "https://cortex-prod.generalrobotics.dev/cortex")
54
+ final_base_url = base_url or os.getenv("GRID_CORTEX_BASE_URL", DEFAULT_BASE_URL)
55
55
  logger.info(f"HTTPClient initialized for base URL: {final_base_url}")
56
56
 
57
57
  self._client = httpx.Client(base_url=final_base_url, timeout=timeout, headers=headers)
@@ -75,7 +75,6 @@ class HTTPClient:
75
75
  headers.setdefault("Content-Type", "application/msgpack")
76
76
  resp = self._client.post(path, content=data, headers=headers, timeout=timeout)
77
77
  else:
78
- # JSON fall-back (legacy)
79
78
  headers = headers or {"Content-Type": "application/json"}
80
79
  resp = self._client.post(path, json=json, data=data, headers=headers, timeout=timeout)
81
80
  resp.raise_for_status()
@@ -170,7 +169,7 @@ class AsyncHTTPClient:
170
169
  else:
171
170
  headers["x-api-key"] = api_key
172
171
 
173
- final_base_url = base_url or os.getenv("GRID_CORTEX_BASE_URL", "https://cortex-prod.generalrobotics.dev/cortex")
172
+ final_base_url = base_url or os.getenv("GRID_CORTEX_BASE_URL", DEFAULT_BASE_URL)
174
173
  logger.info(f"AsyncHTTPClient initialized for base URL: {final_base_url}")
175
174
 
176
175
  self._client = httpx.AsyncClient(base_url=final_base_url, timeout=timeout, headers=headers)
@@ -84,7 +84,7 @@ class CortexHubClient:
84
84
 
85
85
  Args:
86
86
  api_key: API key (defaults to GRID_CORTEX_API_KEY env var)
87
- base_url: Base URL (defaults to GRID_CORTEX_BASE_URL env var or production).
87
+ base_url: Base URL (defaults to the GRID_CORTEX_BASE_URL env var, or production if unset).
88
88
  The WebSocket endpoint is derived from the `/ws` route prefix (ends up as `/ws/ws`).
89
89
  timeout: Socket timeout in seconds
90
90
 
@@ -108,9 +108,9 @@ class CortexHubClient:
108
108
  base_url: Optional[str] = None,
109
109
  timeout: float = 60.0,
110
110
  ):
111
- self._api_key = api_key or os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
111
+ self._api_key = api_key or os.getenv("GRID_CORTEX_API_KEY")
112
112
  if not self._api_key:
113
- logger.warning("API key not set. Set GRID_CORTEX_API_KEY or CORTEX_API_KEY.")
113
+ logger.warning("API key not set. Set GRID_CORTEX_API_KEY.")
114
114
  self._base_url = base_url
115
115
  self._url = self._resolve_ws_url(base_url)
116
116
  self._timeout = timeout
@@ -135,6 +135,8 @@ class PI05(BaseModel):
135
135
  gripper: Union[np.ndarray, list],
136
136
  state: Union[np.ndarray, list],
137
137
  prompt: Optional[str] = None,
138
+ rtc_kwargs: Optional[Dict[str, Any]] = None,
139
+ prev_chunk: Optional[Union[np.ndarray, list]] = None,
138
140
  ) -> Dict[str, Any]:
139
141
  """Convert inputs to the payload expected by the server.
140
142
 
@@ -145,6 +147,13 @@ class PI05(BaseModel):
145
147
  gripper: Gripper position.
146
148
  state: Robot state (concatenation of joints and gripper).
147
149
  prompt: Optional task prompt.
150
+ rtc_kwargs: Optional real-time-chunking params. When set, the server
151
+ routes through the RTC path (model.realtime_action). Expected
152
+ keys: ``rtc_current_index`` (steps of the previous chunk already
153
+ executed), ``rtc_frozen_until``, ``rtc_thaw_until``.
154
+ prev_chunk: Previous predicted action chunk, fed back as RTC guidance.
155
+ None on the first call; on later calls pass the ``prev_chunk``
156
+ returned by the previous inference.
148
157
 
149
158
  Returns:
150
159
  Dictionary that will be msgpack-encoded and sent to the server.
@@ -180,6 +189,13 @@ class PI05(BaseModel):
180
189
  "gripper": gripper_arr,
181
190
  "state": state_arr,
182
191
  }
192
+ # Real-time chunking (optional). Presence of rtc_kwargs is what makes the
193
+ # server take the RTC path; prev_chunk is the guidance chunk (None → the
194
+ # server bootstraps one on the first call).
195
+ if rtc_kwargs is not None:
196
+ obs["rtc_kwargs"] = rtc_kwargs
197
+ if prev_chunk is not None:
198
+ obs["prev_chunk"] = np.asarray(prev_chunk, dtype=np.float32)
183
199
 
184
200
  payload = {"obs": obs}
185
201
  if prompt is not None:
@@ -235,6 +251,8 @@ class PI05(BaseModel):
235
251
  gripper: Union[np.ndarray, list],
236
252
  state: Union[np.ndarray, list],
237
253
  prompt: Optional[str] = None,
254
+ rtc_kwargs: Optional[Dict[str, Any]] = None,
255
+ prev_chunk: Optional[Union[np.ndarray, list]] = None,
238
256
  timeout: float | None = None,
239
257
  ) -> Dict[str, Any]:
240
258
  """Run PI05 policy inference on robot observations.
@@ -246,11 +264,17 @@ class PI05(BaseModel):
246
264
  gripper: Gripper position as numpy array or list.
247
265
  state: Robot state as numpy array or list (concatenation of joints and gripper).
248
266
  prompt: Optional task prompt string.
267
+ rtc_kwargs: Optional real-time-chunking params (see :py:meth:`preprocess`).
268
+ When set, the server runs the RTC path and returns a ``prev_chunk``
269
+ field to feed back on the next call.
270
+ prev_chunk: Previous predicted chunk fed back as RTC guidance (None on
271
+ the first call).
249
272
  timeout: Optional timeout in seconds for the HTTP request.
250
273
 
251
274
  Returns:
252
275
  Action dictionary containing:
253
276
  - "actions": numpy array of shape (horizon, action_dim) with predicted actions
277
+ - "prev_chunk": (RTC only) chunk to feed back on the next call
254
278
  - Other fields from policy.infer() (e.g., "state", "policy_timing", etc.)
255
279
 
256
280
  Raises:
@@ -284,5 +308,7 @@ class PI05(BaseModel):
284
308
  gripper=gripper,
285
309
  state=state,
286
310
  prompt=prompt,
311
+ rtc_kwargs=rtc_kwargs,
312
+ prev_chunk=prev_chunk,
287
313
  timeout=timeout,
288
314
  )
@@ -112,9 +112,9 @@ class TestCRadioHTTP(BaseModelTestHTTP):
112
112
  @pytest.mark.asyncio
113
113
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
114
114
  """Test C-RADIO inference via CortexHubClient (WebSocket)."""
115
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
115
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
116
116
  if not api_key:
117
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
117
+ pytest.skip("GRID_CORTEX_API_KEY not set")
118
118
 
119
119
  async with CortexHubClient(api_key=api_key) as hub:
120
120
  emb = await hub.run(ModelType.C_RADIO, image_input=rgb_image_np)
@@ -268,9 +268,9 @@ class TestContactGraspNetHTTP(BaseModelTestHTTP):
268
268
  camera_intrinsics: np.ndarray,
269
269
  aux_args: dict,
270
270
  ):
271
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
271
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
272
272
  if not api_key:
273
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
273
+ pytest.skip("GRID_CORTEX_API_KEY not set")
274
274
 
275
275
  async with CortexHubClient(api_key=api_key) as hub:
276
276
  result = await hub.run(
@@ -21,9 +21,9 @@ class TestCortexHubClient:
21
21
  @pytest_asyncio.fixture
22
22
  async def hub(self):
23
23
  """Create connected CortexHubClient instance."""
24
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
24
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
25
25
  if not api_key:
26
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
26
+ pytest.skip("GRID_CORTEX_API_KEY not set")
27
27
 
28
28
  hub = CortexHubClient(api_key=api_key)
29
29
  await hub.connect()
@@ -33,9 +33,9 @@ class TestCortexHubClient:
33
33
  @pytest.mark.asyncio
34
34
  async def test_connect_disconnect(self):
35
35
  """Test connection lifecycle."""
36
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
36
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
37
37
  if not api_key:
38
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
38
+ pytest.skip("GRID_CORTEX_API_KEY not set")
39
39
 
40
40
  hub = CortexHubClient(api_key=api_key)
41
41
  assert not hub.is_connected
@@ -49,9 +49,9 @@ class TestCortexHubClient:
49
49
  @pytest.mark.asyncio
50
50
  async def test_context_manager(self, rgb_image_np: np.ndarray):
51
51
  """Test async context manager usage."""
52
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
52
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
53
53
  if not api_key:
54
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
54
+ pytest.skip("GRID_CORTEX_API_KEY not set")
55
55
 
56
56
  async with CortexHubClient(api_key=api_key) as hub:
57
57
  assert hub.is_connected
@@ -290,9 +290,9 @@ class TestCortexHubClient:
290
290
  @pytest.mark.asyncio
291
291
  async def test_not_connected_error(self, rgb_image_np: np.ndarray):
292
292
  """Test error when calling run without connecting."""
293
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
293
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
294
294
  if not api_key:
295
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
295
+ pytest.skip("GRID_CORTEX_API_KEY not set")
296
296
 
297
297
  hub = CortexHubClient(api_key=api_key)
298
298
  # Don't connect
@@ -307,9 +307,9 @@ class TestCortexHubClientPubSub:
307
307
  @pytest_asyncio.fixture
308
308
  async def hub(self):
309
309
  """Create connected CortexHubClient instance."""
310
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
310
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
311
311
  if not api_key:
312
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
312
+ pytest.skip("GRID_CORTEX_API_KEY not set")
313
313
 
314
314
  hub = CortexHubClient(api_key=api_key)
315
315
  await hub.connect()
@@ -416,8 +416,10 @@ class TestCortexHubClientPubSub:
416
416
  class TestCortexHubClientURLResolution:
417
417
  """Tests for URL resolution (no network needed)."""
418
418
 
419
- def test_default_url_is_production(self):
420
- """Test default URL points to production with /ws/ws suffix."""
419
+ def test_default_url_is_prod(self, monkeypatch):
420
+ """Test default URL points to prod with /ws/ws suffix."""
421
+ monkeypatch.delenv("GRID_TARGET_ENV", raising=False)
422
+ monkeypatch.delenv("GRID_CORTEX_BASE_URL", raising=False)
421
423
  hub = CortexHubClient(api_key="test")
422
424
  assert "cortex-prod" in hub.url
423
425
  assert hub.url.endswith("/ws/ws")
@@ -108,9 +108,9 @@ class TestDA3MetricHTTP(BaseModelTestHTTP):
108
108
  @pytest.mark.asyncio
109
109
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
110
110
  """Test DA3Metric inference via CortexHubClient (WebSocket)."""
111
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
111
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
112
112
  if not api_key:
113
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
113
+ pytest.skip("GRID_CORTEX_API_KEY not set")
114
114
 
115
115
  async with CortexHubClient(api_key=api_key) as hub:
116
116
  depth = await hub.run(ModelType.DA3METRIC, image_input=rgb_image_np)
@@ -275,9 +275,9 @@ class TestFastFoundationStereoHTTP(BaseModelTestHTTP):
275
275
  @pytest.mark.asyncio
276
276
  async def test_cortex_hub(self, stereo_pair: tuple, aux_args: dict):
277
277
  """Test Fast-FoundationStereo inference via CortexHubClient (WebSocket)."""
278
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
278
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
279
279
  if not api_key:
280
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
280
+ pytest.skip("GRID_CORTEX_API_KEY not set")
281
281
 
282
282
  left, right = stereo_pair
283
283
  async with CortexHubClient(api_key=api_key) as hub:
@@ -268,9 +268,9 @@ class TestFoundationStereoHTTP(BaseModelTestHTTP):
268
268
  @pytest.mark.asyncio
269
269
  async def test_cortex_hub(self, stereo_pair: tuple, aux_args: dict):
270
270
  """Test FoundationStereo inference via CortexHubClient (WebSocket)."""
271
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
271
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
272
272
  if not api_key:
273
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
273
+ pytest.skip("GRID_CORTEX_API_KEY not set")
274
274
 
275
275
  left, right = stereo_pair
276
276
  async with CortexHubClient(api_key=api_key) as hub:
@@ -363,9 +363,9 @@ class TestGraspGenHTTP(BaseModelTestHTTP):
363
363
  aux_args: dict,
364
364
  ):
365
365
  """Test GraspGen inference via CortexHubClient (WebSocket)."""
366
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
366
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
367
367
  if not api_key:
368
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
368
+ pytest.skip("GRID_CORTEX_API_KEY not set")
369
369
 
370
370
  async with CortexHubClient(api_key=api_key) as hub:
371
371
  result = await hub.run(
@@ -135,9 +135,9 @@ class TestGraspGenXHTTP(BaseModelTestHTTP):
135
135
  @pytest.mark.asyncio
136
136
  async def test_cortex_hub(self, point_cloud: np.ndarray, aux_args: dict):
137
137
  """Inference via CortexHubClient (WebSocket)."""
138
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
138
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
139
139
  if not api_key:
140
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
140
+ pytest.skip("GRID_CORTEX_API_KEY not set")
141
141
  async with CortexHubClient(api_key=api_key) as hub:
142
142
  result = await hub.run(ModelType.GRASPGENX, point_cloud=point_cloud, aux_args=aux_args)
143
143
  assert result is not None
@@ -191,9 +191,9 @@ class TestGSAM2HTTP(BaseModelTestHTTP):
191
191
  @pytest.mark.asyncio
192
192
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
193
193
  """Test GSAM2 inference via CortexHubClient (WebSocket)."""
194
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
194
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
195
195
  if not api_key:
196
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
196
+ pytest.skip("GRID_CORTEX_API_KEY not set")
197
197
 
198
198
  async with CortexHubClient(api_key=api_key) as hub:
199
199
  result = await hub.run(ModelType.GSAM2, image_input=rgb_image_np, prompt="object")
@@ -189,9 +189,9 @@ class TestLocateAnythingHTTP(BaseModelTestHTTP):
189
189
  @pytest.mark.asyncio
190
190
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
191
191
  """Test LocateAnything inference via CortexHubClient (WebSocket)."""
192
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
192
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
193
193
  if not api_key:
194
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
194
+ pytest.skip("GRID_CORTEX_API_KEY not set")
195
195
 
196
196
  async with CortexHubClient(api_key=api_key) as hub:
197
197
  result = await hub.run(ModelType.LOCATE_ANYTHING, image_input=rgb_image_np, task="detect", prompt="cat")
@@ -134,9 +134,9 @@ class TestMetric3DHTTP(BaseModelTestHTTP):
134
134
  @pytest.mark.asyncio
135
135
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
136
136
  """Test Metric3D inference via CortexHubClient (WebSocket)."""
137
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
137
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
138
138
  if not api_key:
139
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
139
+ pytest.skip("GRID_CORTEX_API_KEY not set")
140
140
 
141
141
  async with CortexHubClient(api_key=api_key) as hub:
142
142
  result = await hub.run(ModelType.METRIC3D, image_input=rgb_image_np)
@@ -228,9 +228,9 @@ class TestMoondreamHTTP(BaseModelTestHTTP):
228
228
  @pytest.mark.asyncio
229
229
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
230
230
  """Test Moondream inference via CortexHubClient (WebSocket)."""
231
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
231
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
232
232
  if not api_key:
233
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
233
+ pytest.skip("GRID_CORTEX_API_KEY not set")
234
234
 
235
235
  async with CortexHubClient(api_key=api_key) as hub:
236
236
  result = await hub.run(ModelType.MOONDREAM, image_input=rgb_image_np, task="caption", length="short")
@@ -193,9 +193,9 @@ class TestOneFormerHTTP(BaseModelTestHTTP):
193
193
  @pytest.mark.asyncio
194
194
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
195
195
  """Test OneFormer inference via CortexHubClient (WebSocket)."""
196
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
196
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
197
197
  if not api_key:
198
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
198
+ pytest.skip("GRID_CORTEX_API_KEY not set")
199
199
 
200
200
  async with CortexHubClient(api_key=api_key) as hub:
201
201
  result = await hub.run(ModelType.ONEFORMER, image_input=rgb_image_np, mode="panoptic")
@@ -224,9 +224,9 @@ class TestOWLv2HTTP(BaseModelTestHTTP):
224
224
  @pytest.mark.asyncio
225
225
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
226
226
  """Test OWLv2 inference via CortexHubClient (WebSocket)."""
227
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
227
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
228
228
  if not api_key:
229
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
229
+ pytest.skip("GRID_CORTEX_API_KEY not set")
230
230
 
231
231
  async with CortexHubClient(api_key=api_key) as hub:
232
232
  result = await hub.run(ModelType.OWLV2, image_input=rgb_image_np, prompt="cat . dog")
@@ -194,9 +194,9 @@ class TestPI05HTTP(BaseModelTestHTTP):
194
194
  @pytest.mark.asyncio
195
195
  async def test_cortex_hub(self):
196
196
  """Test PI05 inference via CortexHubClient (WebSocket)."""
197
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
197
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
198
198
  if not api_key:
199
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
199
+ pytest.skip("GRID_CORTEX_API_KEY not set")
200
200
 
201
201
  inputs = self._create_test_inputs()
202
202
  async with CortexHubClient(api_key=api_key) as hub:
@@ -170,9 +170,9 @@ class TestQwenVLHTTP(BaseModelTestHTTP):
170
170
  @pytest.mark.asyncio
171
171
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
172
172
  """Test Qwen VL inference via CortexHubClient (WebSocket)."""
173
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
173
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
174
174
  if not api_key:
175
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
175
+ pytest.skip("GRID_CORTEX_API_KEY not set")
176
176
 
177
177
  async with CortexHubClient(api_key=api_key) as hub:
178
178
  result = await hub.run(ModelType.QWEN_VL, image_input=rgb_image_np, prompt="Describe this image.")
@@ -215,9 +215,9 @@ class TestSAM2HTTP(BaseModelTestHTTP):
215
215
  @pytest.mark.asyncio
216
216
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
217
217
  """Test SAM2 inference via CortexHubClient (WebSocket)."""
218
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
218
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
219
219
  if not api_key:
220
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
220
+ pytest.skip("GRID_CORTEX_API_KEY not set")
221
221
 
222
222
  async with CortexHubClient(api_key=api_key) as hub:
223
223
  result = await hub.run(ModelType.SAM2, image_input=rgb_image_np, prompts=[[320, 240]], labels=[1])
@@ -303,9 +303,9 @@ class TestSAM3HTTP(BaseModelTestHTTP):
303
303
  @pytest.mark.asyncio
304
304
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
305
305
  """Test SAM3 inference via CortexHubClient (WebSocket)."""
306
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
306
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
307
307
  if not api_key:
308
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
308
+ pytest.skip("GRID_CORTEX_API_KEY not set")
309
309
 
310
310
  async with CortexHubClient(api_key=api_key) as hub:
311
311
  result = await hub.run(ModelType.SAM3, image_input=rgb_image_np, text="object")
@@ -185,9 +185,9 @@ class TestUR5ePyrokiCollisionBatchHTTP(BaseModelTestHTTP):
185
185
  @pytest.mark.asyncio
186
186
  async def test_cortex_hub(self, collision_batch_payload: dict):
187
187
  """Test UR5e PyRoKi Collision Batch inference via CortexHubClient (WebSocket)."""
188
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
188
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
189
189
  if not api_key:
190
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
190
+ pytest.skip("GRID_CORTEX_API_KEY not set")
191
191
 
192
192
  async with CortexHubClient(api_key=api_key) as hub:
193
193
  result = await hub.run(ModelType.UR5E_PYROKI_COLLISION_BATCH, **collision_batch_payload)
@@ -244,9 +244,9 @@ class TestUR5ePyrokiFkHTTP(BaseModelTestHTTP):
244
244
  @pytest.mark.asyncio
245
245
  async def test_cortex_hub(self, batch_joint_states_np: np.ndarray):
246
246
  """Test UR5e PyRoKi FK inference via CortexHubClient (WebSocket)."""
247
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
247
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
248
248
  if not api_key:
249
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
249
+ pytest.skip("GRID_CORTEX_API_KEY not set")
250
250
 
251
251
  async with CortexHubClient(api_key=api_key) as hub:
252
252
  result = await hub.run(ModelType.UR5E_PYROKI_FK, batch_joint_states=batch_joint_states_np)
@@ -113,9 +113,9 @@ class TestZoeDepthHTTP(BaseModelTestHTTP):
113
113
  @pytest.mark.asyncio
114
114
  async def test_cortex_hub(self, rgb_image_np: np.ndarray):
115
115
  """Test ZoeDepth inference via CortexHubClient (WebSocket)."""
116
- api_key = os.getenv("GRID_CORTEX_API_KEY") or os.getenv("CORTEX_API_KEY")
116
+ api_key = os.getenv("GRID_CORTEX_API_KEY")
117
117
  if not api_key:
118
- pytest.skip("GRID_CORTEX_API_KEY or CORTEX_API_KEY not set")
118
+ pytest.skip("GRID_CORTEX_API_KEY not set")
119
119
 
120
120
  async with CortexHubClient(api_key=api_key) as hub:
121
121
  depth = await hub.run(ModelType.ZOEDEPTH, image_input=rgb_image_np)