abstract-client 0.2.1__tar.gz → 0.2.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: abstract-client
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Abstract's robot API from Python: action chunks from served robot models, sync and asyncio.
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -19,6 +19,35 @@ action chunk per `predict()`.
19
19
  uv add abstract-client
20
20
  ```
21
21
 
22
+ ### Quickstart (0.2.2)
23
+
24
+ ```python
25
+ import abstract
26
+
27
+ checkpoint = "nvidia/dreamzero"
28
+ embodiment = "yam"
29
+ client = abstract.client(ABSTRACT_API_KEY, checkpoint, embodiment)
30
+
31
+ client.set_observation(frames, observation)
32
+ action = client.get_action()
33
+ client.reset_episode()
34
+ client.close()
35
+ ```
36
+
37
+ `ABSTRACT_API_KEY` is your key, `frames` maps each camera to JPEG bytes, and `observation`
38
+ holds `prompt` (the task) and `state` (measured alongside the frames). The YAM camera and
39
+ state fields are shown below. The returned `Chunk` contains targets, never hardware motion;
40
+ reset ends the model's episode without repositioning the robot.
41
+
42
+ `abstract.client()` checks the account's unmetered model catalogue before configuring an
43
+ `AtomsClient`. The checkpoint must be available and its `robot` must match `embodiment`.
44
+ It does not adapt models to other robots. Omit `api_key` to use the environment or saved
45
+ CLI credentials; connection options such as `base_url` and `timeout` pass through to the
46
+ existing client. Context managers and the existing `atoms` interface remain supported.
47
+
48
+ Release order: publish the matching 0.2.2 SDK before deploying the new landing snippet and
49
+ quickstart; older wheels do not provide `import abstract`.
50
+
22
51
  This is all a robot with its own stack needs. The `abstract` command and the robot station are
23
52
  `abstract-robots`, built on it, and `abstract-atoms` installs both (`apps/atoms`).
24
53
 
@@ -27,7 +56,7 @@ import atoms
27
56
 
28
57
  client = atoms.Client() # the key: api_key=, else ABSTRACT_API_KEY, else `abstract login`'s file
29
58
 
30
- with client.connect("abstract/dreamzero-astra", "fold the towel") as policy:
59
+ with client.connect("nvidia/dreamzero", "fold the towel") as policy:
31
60
  frames = {"overhead": top_jpeg, "wrist_l": left_jpeg, "wrist_r": right_jpeg}
32
61
  while not done:
33
62
  state = {
@@ -58,10 +87,11 @@ These interfaces require `abstract-client` 0.2.0 or later.
58
87
  `client.get_models()` is the availability source; an SDK adapter does not mean a checkpoint
59
88
  is enabled on the account. These native contracts are separate from the YAM example:
60
89
 
61
- | Model | Observation | Returned commands |
62
- |---|---|---|
63
- | `xiaomi/xiaomi-robotics-1` | RoboDojo ARX X5 world-frame poses, normalized grippers (0 closed, 1 open), and `left_joint_position` / `right_joint_position` with six measured radians each. Cameras retain `overhead`, `wrist_l`, `wrist_r`. | `chunk.left` / `chunk.right`: 30 end-effector targets at 25 Hz, in the same RoboDojo world frame. |
64
- | `black-forest-labs/flux-3-action` | DROID Franka `joint_position` (seven radians), `gripper_position` (one closed fraction: 0 open, 1 closed), and cameras `exterior_image_0_left`, `exterior_image_1_left`, `wrist_image_left`. | `chunk.joints`: 32 rows of seven absolute joint targets plus gripper at 15 Hz; `chunk.action_space == "joint_position"`. `left` and `right` are empty. |
90
+ | Model | Observation | Returned commands |
91
+ | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
92
+ | `verne/v0.5` | The YAM example's poses and cameras, one frame per camera and then four; not trained on the YAM | 18 pose rows per arm at 30 Hz |
93
+ | `xiaomi/xiaomi-robotics-1` | RoboDojo ARX X5 world-frame poses, normalized grippers (0 closed, 1 open), and `left_joint_position` / `right_joint_position` with six measured radians each. Cameras retain `overhead`, `wrist_l`, `wrist_r`. | `chunk.left` / `chunk.right`: 30 end-effector targets at 25 Hz, in the same RoboDojo world frame. |
94
+ | `black-forest-labs/flux-3-action` | DROID Franka `joint_position` (seven radians), `gripper_position` (one closed fraction: 0 open, 1 closed), and cameras `exterior_image_0_left`, `exterior_image_1_left`, `wrist_image_left`. | `chunk.joints`: 32 rows of seven absolute joint targets plus gripper at 15 Hz; `chunk.action_space == "joint_position"`. `left` and `right` are empty. |
65
95
 
66
96
  Use `chunk.row_count` for either command format. `elapsed_rows`, sync/async policies, retries
67
97
  and the `AtomsClient` observation window work with both. Policies sharing one observation
@@ -77,7 +107,7 @@ pull a chunk when it says so.
77
107
  from concurrent.futures import ThreadPoolExecutor
78
108
 
79
109
  robot = atoms.AtomsClient() # the key, as atoms.Client finds it
80
- robot.policy({"model": "abstract/dreamzero-astra"})
110
+ robot.policy({"model": "nvidia/dreamzero"})
81
111
  with robot, ThreadPoolExecutor(1) as worker: # the request runs while the robot moves
82
112
  chunk, row, pending = None, 0, None
83
113
  while not done:
@@ -102,26 +132,24 @@ with its own episode, frames (DreamZero takes four per camera, MolmoAct2 one), p
102
132
  One drives the arms; the others answer the same observations, to compare them.
103
133
 
104
134
  ```python
105
- robot.policies(
106
- {"dz": {"model": "abstract/dreamzero-astra"}, "molmo": {"model": "allenai/molmoact2"}}
107
- )
135
+ robot.policies({"dz": {"model": "nvidia/dreamzero"}, "molmo": {"model": "allenai/molmoact2"}})
108
136
  robot.set_observation(frames, observation) # one tick, every model
109
137
  answers = robot.get_actions() # every model at once: {name: Chunk, or the error it raised}
110
138
  drive = robot["dz"] # one model: get_action(), refill_due(), last, mode, last_timing
111
139
  ```
112
140
 
113
- | DreamClient | atoms.AtomsClient |
114
- |---|---|
115
- | `DreamClient(api_key)` | `AtomsClient(api_key)`, or `AtomsClient(client=...)` |
116
- | `get_models()` | `get_models()`: served models and your fine-tunes, with their rates |
117
- | `policy({"checkpoint": ...})` | `policy({"model": ...})`; `execution_horizon`, `action_hz`, `sync_above_ms`, `timeout_ms` as in DreamClient |
118
- | `set_observation(frames, observation, timestamp=)` | the same: `video.<camera>` frames, `prompt` and `state` (a dict or `state.<name>` keys) |
119
- | `get_action()` returns joint chunks | `get_action()` returns a `Chunk` in the selected model's action space: poses in `left` / `right`, native joint commands in `joints` |
120
- | `reset_episode()`, `refill_due()`, `close()` | the same |
121
- | `mode`, `execution_horizon`, `action_hz`, `last_timing`, `checkpoint`, `session_id` | the same, `model` for `checkpoint` |
122
- | `obs_window`, `obs_fps` | none: each answer says how many frames the next observation carries |
123
- | `DreamSlowNetworkWarning` | `atoms.SlowNetworkWarning` |
124
- | one model per client | `policies({name: config})`, `get_actions()`, `robot[name]` |
141
+ | DreamClient | atoms.AtomsClient |
142
+ | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
143
+ | `DreamClient(api_key)` | `AtomsClient(api_key)`, or `AtomsClient(client=...)` |
144
+ | `get_models()` | `get_models()`: served models and your fine-tunes, with their rates |
145
+ | `policy({"checkpoint": ...})` | `policy({"model": ...})`; `execution_horizon`, `action_hz`, `sync_above_ms`, `timeout_ms` as in DreamClient |
146
+ | `set_observation(frames, observation, timestamp=)` | the same: `video.<camera>` frames, `prompt` and `state` (a dict or `state.<name>` keys) |
147
+ | `get_action()` returns joint chunks | `get_action()` returns a `Chunk` in the selected model's action space: poses in `left` / `right`, native joint commands in `joints` |
148
+ | `reset_episode()`, `refill_due()`, `close()` | the same |
149
+ | `mode`, `execution_horizon`, `action_hz`, `last_timing`, `checkpoint`, `session_id` | the same, `model` for `checkpoint` |
150
+ | `obs_window`, `obs_fps` | none: each answer says how many frames the next observation carries |
151
+ | `DreamSlowNetworkWarning` | `atoms.SlowNetworkWarning` |
152
+ | one model per client | `policies({name: config})`, `get_actions()`, `robot[name]` |
125
153
 
126
154
  Not here yet: DreamClient's seam smoothing (`commanded`), datasets and fine-tuning. Embodiments,
127
155
  `ik` and Live View have no counterpart on this API.
@@ -8,6 +8,35 @@ action chunk per `predict()`.
8
8
  uv add abstract-client
9
9
  ```
10
10
 
11
+ ### Quickstart (0.2.2)
12
+
13
+ ```python
14
+ import abstract
15
+
16
+ checkpoint = "nvidia/dreamzero"
17
+ embodiment = "yam"
18
+ client = abstract.client(ABSTRACT_API_KEY, checkpoint, embodiment)
19
+
20
+ client.set_observation(frames, observation)
21
+ action = client.get_action()
22
+ client.reset_episode()
23
+ client.close()
24
+ ```
25
+
26
+ `ABSTRACT_API_KEY` is your key, `frames` maps each camera to JPEG bytes, and `observation`
27
+ holds `prompt` (the task) and `state` (measured alongside the frames). The YAM camera and
28
+ state fields are shown below. The returned `Chunk` contains targets, never hardware motion;
29
+ reset ends the model's episode without repositioning the robot.
30
+
31
+ `abstract.client()` checks the account's unmetered model catalogue before configuring an
32
+ `AtomsClient`. The checkpoint must be available and its `robot` must match `embodiment`.
33
+ It does not adapt models to other robots. Omit `api_key` to use the environment or saved
34
+ CLI credentials; connection options such as `base_url` and `timeout` pass through to the
35
+ existing client. Context managers and the existing `atoms` interface remain supported.
36
+
37
+ Release order: publish the matching 0.2.2 SDK before deploying the new landing snippet and
38
+ quickstart; older wheels do not provide `import abstract`.
39
+
11
40
  This is all a robot with its own stack needs. The `abstract` command and the robot station are
12
41
  `abstract-robots`, built on it, and `abstract-atoms` installs both (`apps/atoms`).
13
42
 
@@ -16,7 +45,7 @@ import atoms
16
45
 
17
46
  client = atoms.Client() # the key: api_key=, else ABSTRACT_API_KEY, else `abstract login`'s file
18
47
 
19
- with client.connect("abstract/dreamzero-astra", "fold the towel") as policy:
48
+ with client.connect("nvidia/dreamzero", "fold the towel") as policy:
20
49
  frames = {"overhead": top_jpeg, "wrist_l": left_jpeg, "wrist_r": right_jpeg}
21
50
  while not done:
22
51
  state = {
@@ -47,10 +76,11 @@ These interfaces require `abstract-client` 0.2.0 or later.
47
76
  `client.get_models()` is the availability source; an SDK adapter does not mean a checkpoint
48
77
  is enabled on the account. These native contracts are separate from the YAM example:
49
78
 
50
- | Model | Observation | Returned commands |
51
- |---|---|---|
52
- | `xiaomi/xiaomi-robotics-1` | RoboDojo ARX X5 world-frame poses, normalized grippers (0 closed, 1 open), and `left_joint_position` / `right_joint_position` with six measured radians each. Cameras retain `overhead`, `wrist_l`, `wrist_r`. | `chunk.left` / `chunk.right`: 30 end-effector targets at 25 Hz, in the same RoboDojo world frame. |
53
- | `black-forest-labs/flux-3-action` | DROID Franka `joint_position` (seven radians), `gripper_position` (one closed fraction: 0 open, 1 closed), and cameras `exterior_image_0_left`, `exterior_image_1_left`, `wrist_image_left`. | `chunk.joints`: 32 rows of seven absolute joint targets plus gripper at 15 Hz; `chunk.action_space == "joint_position"`. `left` and `right` are empty. |
79
+ | Model | Observation | Returned commands |
80
+ | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
81
+ | `verne/v0.5` | The YAM example's poses and cameras, one frame per camera and then four; not trained on the YAM | 18 pose rows per arm at 30 Hz |
82
+ | `xiaomi/xiaomi-robotics-1` | RoboDojo ARX X5 world-frame poses, normalized grippers (0 closed, 1 open), and `left_joint_position` / `right_joint_position` with six measured radians each. Cameras retain `overhead`, `wrist_l`, `wrist_r`. | `chunk.left` / `chunk.right`: 30 end-effector targets at 25 Hz, in the same RoboDojo world frame. |
83
+ | `black-forest-labs/flux-3-action` | DROID Franka `joint_position` (seven radians), `gripper_position` (one closed fraction: 0 open, 1 closed), and cameras `exterior_image_0_left`, `exterior_image_1_left`, `wrist_image_left`. | `chunk.joints`: 32 rows of seven absolute joint targets plus gripper at 15 Hz; `chunk.action_space == "joint_position"`. `left` and `right` are empty. |
54
84
 
55
85
  Use `chunk.row_count` for either command format. `elapsed_rows`, sync/async policies, retries
56
86
  and the `AtomsClient` observation window work with both. Policies sharing one observation
@@ -66,7 +96,7 @@ pull a chunk when it says so.
66
96
  from concurrent.futures import ThreadPoolExecutor
67
97
 
68
98
  robot = atoms.AtomsClient() # the key, as atoms.Client finds it
69
- robot.policy({"model": "abstract/dreamzero-astra"})
99
+ robot.policy({"model": "nvidia/dreamzero"})
70
100
  with robot, ThreadPoolExecutor(1) as worker: # the request runs while the robot moves
71
101
  chunk, row, pending = None, 0, None
72
102
  while not done:
@@ -91,26 +121,24 @@ with its own episode, frames (DreamZero takes four per camera, MolmoAct2 one), p
91
121
  One drives the arms; the others answer the same observations, to compare them.
92
122
 
93
123
  ```python
94
- robot.policies(
95
- {"dz": {"model": "abstract/dreamzero-astra"}, "molmo": {"model": "allenai/molmoact2"}}
96
- )
124
+ robot.policies({"dz": {"model": "nvidia/dreamzero"}, "molmo": {"model": "allenai/molmoact2"}})
97
125
  robot.set_observation(frames, observation) # one tick, every model
98
126
  answers = robot.get_actions() # every model at once: {name: Chunk, or the error it raised}
99
127
  drive = robot["dz"] # one model: get_action(), refill_due(), last, mode, last_timing
100
128
  ```
101
129
 
102
- | DreamClient | atoms.AtomsClient |
103
- |---|---|
104
- | `DreamClient(api_key)` | `AtomsClient(api_key)`, or `AtomsClient(client=...)` |
105
- | `get_models()` | `get_models()`: served models and your fine-tunes, with their rates |
106
- | `policy({"checkpoint": ...})` | `policy({"model": ...})`; `execution_horizon`, `action_hz`, `sync_above_ms`, `timeout_ms` as in DreamClient |
107
- | `set_observation(frames, observation, timestamp=)` | the same: `video.<camera>` frames, `prompt` and `state` (a dict or `state.<name>` keys) |
108
- | `get_action()` returns joint chunks | `get_action()` returns a `Chunk` in the selected model's action space: poses in `left` / `right`, native joint commands in `joints` |
109
- | `reset_episode()`, `refill_due()`, `close()` | the same |
110
- | `mode`, `execution_horizon`, `action_hz`, `last_timing`, `checkpoint`, `session_id` | the same, `model` for `checkpoint` |
111
- | `obs_window`, `obs_fps` | none: each answer says how many frames the next observation carries |
112
- | `DreamSlowNetworkWarning` | `atoms.SlowNetworkWarning` |
113
- | one model per client | `policies({name: config})`, `get_actions()`, `robot[name]` |
130
+ | DreamClient | atoms.AtomsClient |
131
+ | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
132
+ | `DreamClient(api_key)` | `AtomsClient(api_key)`, or `AtomsClient(client=...)` |
133
+ | `get_models()` | `get_models()`: served models and your fine-tunes, with their rates |
134
+ | `policy({"checkpoint": ...})` | `policy({"model": ...})`; `execution_horizon`, `action_hz`, `sync_above_ms`, `timeout_ms` as in DreamClient |
135
+ | `set_observation(frames, observation, timestamp=)` | the same: `video.<camera>` frames, `prompt` and `state` (a dict or `state.<name>` keys) |
136
+ | `get_action()` returns joint chunks | `get_action()` returns a `Chunk` in the selected model's action space: poses in `left` / `right`, native joint commands in `joints` |
137
+ | `reset_episode()`, `refill_due()`, `close()` | the same |
138
+ | `mode`, `execution_horizon`, `action_hz`, `last_timing`, `checkpoint`, `session_id` | the same, `model` for `checkpoint` |
139
+ | `obs_window`, `obs_fps` | none: each answer says how many frames the next observation carries |
140
+ | `DreamSlowNetworkWarning` | `atoms.SlowNetworkWarning` |
141
+ | one model per client | `policies({name: config})`, `get_actions()`, `robot[name]` |
114
142
 
115
143
  Not here yet: DreamClient's seam smoothing (`commanded`), datasets and fine-tuning. Embodiments,
116
144
  `ik` and Live View have no counterpart on this API.
@@ -16,4 +16,4 @@ build-backend = "hatchling.build"
16
16
  path = "src/atoms/client.py"
17
17
 
18
18
  [tool.hatch.build.targets.wheel]
19
- packages = ["src/atoms"]
19
+ packages = ["src/abstract", "src/atoms"]
@@ -0,0 +1,43 @@
1
+ """A configured robot policy: observations in, action chunks out."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from atoms import AbstractError, AtomsClient, Chunk, ConfigError
8
+
9
+ __all__ = ["AbstractError", "Chunk", "ConfigError", "client"]
10
+
11
+
12
+ def client(
13
+ api_key: str | None = None,
14
+ checkpoint: str | None = None,
15
+ embodiment: str | None = None,
16
+ **options: Any,
17
+ ) -> AtomsClient:
18
+ """Choose an available checkpoint for this robot, then accept observations.
19
+
20
+ Credentials and connection options are those of atoms.AtomsClient. The unmetered
21
+ catalogue validates the checkpoint/embodiment pair; construction never runs a model.
22
+ Embodiment names match the catalogue's robot field, such as ``yam``. Selecting one
23
+ does not adapt a checkpoint to a different robot or connect physical hardware.
24
+ """
25
+ if not isinstance(checkpoint, str) or not checkpoint:
26
+ raise ConfigError("Pass checkpoint as an origin/model id.")
27
+ if not isinstance(embodiment, str) or not embodiment:
28
+ raise ConfigError("Pass embodiment as the checkpoint's robot, such as 'yam'.")
29
+ policy = AtomsClient(api_key, **options)
30
+ try:
31
+ model = next((model for model in policy.get_models() if model.id == checkpoint), None)
32
+ if model is None:
33
+ raise ConfigError(f"Checkpoint {checkpoint!r} is not available to this account.")
34
+ if model.robot != embodiment:
35
+ raise ConfigError(
36
+ f"Checkpoint {checkpoint!r} requires embodiment {model.robot!r}, "
37
+ f"not {embodiment!r}."
38
+ )
39
+ policy.policy({"model": model.id})
40
+ except Exception:
41
+ policy.close()
42
+ raise
43
+ return policy
@@ -3,7 +3,7 @@
3
3
  import atoms
4
4
 
5
5
  client = atoms.Client() # the key: api_key=, else ABSTRACT_API_KEY, else `abstract login`'s
6
- with client.connect("abstract/dreamzero-astra", "fold the towel") as policy:
6
+ with client.connect("nvidia/dreamzero", "fold the towel") as policy:
7
7
  chunk = policy.predict(frames, state)
8
8
 
9
9
  `atoms.AtomsClient` is Dream Labs' DreamClient on this API; `atoms.AsyncClient` is native asyncio.
@@ -39,7 +39,7 @@ from atoms.errors import (
39
39
  )
40
40
  from atoms.policy import AsyncPolicy, Policy, _trace
41
41
 
42
- __version__ = "0.2.1"
42
+ __version__ = "0.2.2"
43
43
 
44
44
  DEFAULT_BASE_URL = "https://api.abstract.inc/v1"
45
45
  API_VERSION = "2026-10-27" # the API this client was built against, pinned in Abstract-Version
File without changes
File without changes
File without changes