puda-comms 0.0.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.
@@ -0,0 +1,310 @@
1
+ Metadata-Version: 2.3
2
+ Name: puda-comms
3
+ Version: 0.0.2
4
+ Summary: Communication library for the PUDA platform.
5
+ Author: zhao
6
+ Author-email: zhao <20024592+agentzhao@users.noreply.github.com>
7
+ Requires-Dist: nats-py>=2.12.0
8
+ Requires-Dist: puda-drivers
9
+ Requires-Dist: pydantic>=2.12.5
10
+ Requires-Python: >=3.14
11
+ Description-Content-Type: text/markdown
12
+
13
+ # Puda Comms
14
+
15
+ A Python module for communication between machines and command services via NATS messaging. Provides client-side services for sending commands, machine-side clients for receiving commands, and data models for structured message exchange.
16
+
17
+ ## Overview
18
+
19
+ The `puda_comms` module enables asynchronous, reliable communication between command services and machines using NATS (NATS JetStream for guaranteed delivery). It handles:
20
+
21
+ - **Command execution**: Send commands to machines and receive responses
22
+ - **Message routing**: Queue commands (sequential execution) and immediate commands (control operations)
23
+ - **State management**: Thread-safe execution state tracking for cancellation and locking
24
+ - **Connection management**: Automatic NATS connection handling with async context managers
25
+
26
+ ## Components
27
+
28
+ The module consists of four main components:
29
+
30
+ ### 1. Models (`models.py`)
31
+
32
+ Data models for structured message exchange. All models use Pydantic for validation and serialization.
33
+
34
+ #### Enums
35
+
36
+ ##### `CommandResponseStatus`
37
+ Status of a command response:
38
+ - `SUCCESS`: Command executed successfully
39
+ - `ERROR`: Command execution failed
40
+
41
+ ##### `CommandResponseCode`
42
+ Error codes for command responses:
43
+ - `COMMAND_CANCELLED`: Command was cancelled before completion
44
+ - `JSON_DECODE_ERROR`: Failed to decode JSON payload
45
+ - `EXECUTION_ERROR`: General execution error
46
+ - `EXECUTION_LOCKED`: Execution is locked (another command is running)
47
+ - `UNKNOWN_COMMAND`: Command name not recognized
48
+ - `PAUSE_ERROR`: Error occurred while pausing execution
49
+ - `RESUME_ERROR`: Error occurred while resuming execution
50
+ - `NO_EXECUTION`: No execution found
51
+ - `RUN_ID_MISMATCH`: Run ID doesn't match current execution
52
+ - `CANCEL_ERROR`: Error occurred while cancelling execution
53
+ - `MACHINE_PAUSED`: Machine is currently paused
54
+
55
+ ##### `MessageType`
56
+ Type of NATS message:
57
+ - `COMMAND`: Command message sent to machine
58
+ - `RESPONSE`: Response message from machine
59
+ - `LOG`: Log message
60
+ - `ALERT`: Alert message
61
+ - `MEDIA`: Media message
62
+
63
+ ##### `ImmediateCommand`
64
+ Command names for immediate/control commands:
65
+ - `PAUSE`: Pause the current execution
66
+ - `RESUME`: Resume a paused execution
67
+ - `CANCEL`: Cancel the current execution
68
+
69
+ #### Data Models
70
+
71
+ ##### `CommandRequest`
72
+ Represents a command to be sent to a machine.
73
+
74
+ **Fields:**
75
+ - `name` (str): The command name to execute
76
+ - `params` (Dict[str, Any]): Command parameters (default: empty dict)
77
+ - `step_number` (int): Execution step number for tracking progress
78
+ - `version` (str): Command version (default: "1.0")
79
+
80
+ **Example:**
81
+ ```python
82
+ command = CommandRequest(
83
+ name="attach_tip",
84
+ params={"slot": "A3", "well": "G8"},
85
+ step_number=2,
86
+ version="1.0"
87
+ )
88
+ ```
89
+
90
+ ##### `CommandResponse`
91
+ Represents the result of a command execution.
92
+
93
+ **Fields:**
94
+ - `status` (CommandResponseStatus): Status of the command response (SUCCESS or ERROR)
95
+ - `completed_at` (str): ISO 8601 UTC timestamp (auto-generated)
96
+ - `code` (Optional[str]): Error code if status is ERROR
97
+ - `message` (Optional[str]): Human-readable error message
98
+
99
+ **Example:**
100
+ ```python
101
+ response = CommandResponse(
102
+ status=CommandResponseStatus.SUCCESS,
103
+ completed_at="2026-01-20T02:00:46Z"
104
+ )
105
+ ```
106
+
107
+ **Error Example:**
108
+ ```python
109
+ error_response = CommandResponse(
110
+ status=CommandResponseStatus.ERROR,
111
+ code="EXECUTION_ERROR",
112
+ message="Failed to attach tip: slot A3 not found",
113
+ completed_at="2026-01-20T02:00:46Z"
114
+ )
115
+ ```
116
+
117
+ ##### `MessageHeader`
118
+ Header metadata for NATS messages.
119
+
120
+ **Fields:**
121
+ - `message_type` (MessageType): Type of message (COMMAND, RESPONSE, LOG, etc.)
122
+ - `version` (str): Message version (default: "1.0")
123
+ - `timestamp` (str): ISO 8601 UTC timestamp (auto-generated)
124
+ - `machine_id` (str): Identifier for the target machine
125
+ - `run_id` (Optional[str]): Unique identifier (UUID) for the run/workflow
126
+
127
+ **Example:**
128
+ ```python
129
+ header = MessageHeader(
130
+ message_type=MessageType.RESPONSE,
131
+ version="1.0",
132
+ timestamp="2026-01-20T02:00:46Z",
133
+ machine_id="first",
134
+ run_id="092073e6-13d0-4756-8d99-eff1612a5a72"
135
+ )
136
+ ```
137
+
138
+ ##### `NATSMessage`
139
+ Complete NATS message structure combining header with optional command or response data.
140
+
141
+ **Fields:**
142
+ - `header` (MessageHeader): Message header (required)
143
+ - `command` (Optional[CommandRequest]): Command request (for command messages)
144
+ - `response` (Optional[CommandResponse]): Command response (for response messages)
145
+
146
+ **Structure:**
147
+ - For command messages: include `header` with `message_type=COMMAND` and `command` field
148
+ - For response messages: include `header` with `message_type=RESPONSE` and `response` field
149
+
150
+ **Complete Message Example:**
151
+ ```json
152
+ {
153
+ "header": {
154
+ "message_type": "response",
155
+ "version": "1.0",
156
+ "timestamp": "2026-01-20T02:00:46Z",
157
+ "machine_id": "first",
158
+ "run_id": "092073e6-13d0-4756-8d99-eff1612a5a72"
159
+ },
160
+ "command": {
161
+ "name": "attach_tip",
162
+ "params": {
163
+ "slot": "A3",
164
+ "well": "G8"
165
+ },
166
+ "step_number": 2,
167
+ "version": "1.0"
168
+ },
169
+ "response": {
170
+ "status": "success",
171
+ "completed_at": "2026-01-20T02:00:46Z",
172
+ "code": null,
173
+ "message": null
174
+ }
175
+ }
176
+ ```
177
+
178
+ ### 2. CommandService (`command_service.py`)
179
+
180
+ Client-side service for sending commands to machines via NATS. Handles:
181
+ - Connecting to NATS servers
182
+ - Sending commands to machines (queue or immediate)
183
+ - Waiting for and handling responses
184
+ - Managing command lifecycle (run_id, step_number, etc.)
185
+ - Automatic connection cleanup via async context manager
186
+
187
+ See [Sending Commands](#sending-commands) section for usage examples.
188
+
189
+ ### 3. MachineClient (`machine_client.py`)
190
+
191
+ Basic default NATS client for generic machines. Handles commands, telemetry, and events following the `puda.{machine_id}.{category}.{sub_category}` pattern. Provides:
192
+ - Subscribing to command streams (queue and immediate) via JetStream with exactly-once delivery
193
+ - Processing incoming commands and sending command responses
194
+ - Publishing telemetry (core NATS, no JetStream)
195
+ - Publishing events (core NATS, fire-and-forget)
196
+ - Connection management and reconnection handling
197
+
198
+ **Note:** This is a generic client. Machine-specific methods should be implemented in the machine-edge client.
199
+
200
+ ### 4. ExecutionState (`execution_state.py`)
201
+
202
+ Thread-safe state management for command execution. Provides:
203
+ - Execution lock to prevent concurrent commands
204
+ - Current task tracking for cancellation
205
+ - Run ID matching for cancel operations
206
+ - Thread-safe access to execution state
207
+
208
+ ## Sending Commands
209
+
210
+ The `CommandService` provides a high-level interface for sending commands to machines via NATS. See [`tests/commands.py`](tests/commands.py) and [`tests/batch_commands.py`](tests/batch_commands.py) for complete examples.
211
+
212
+ ### Recommended Usage: Async Context Manager
213
+
214
+ The recommended way to use `CommandService` is with an async context manager, which automatically handles connection and disconnection. See [`tests/commands.py`](tests/commands.py) for complete examples.
215
+
216
+ ### Command Types
217
+
218
+ #### Queue Commands
219
+
220
+ Queue commands are regular commands that are executed in sequence. Use `send_queue_command()` for machine-specific operations.
221
+
222
+ **Note:** Available commands depend on the machine you are controlling. Different machines support different command sets. See [`puda_drivers`](../drivers/README.md) for information about available commands for each machine type (e.g., `first` machine supports commands like `load_deck`, `attach_tip`, `aspirate_from`, `dispense_to`, `drop_tip`, etc.).
223
+
224
+ Both `send_queue_command()`, `send_queue_commands()`, and `send_immediate_command()` accept an optional `timeout` parameter (default: 120 seconds):
225
+
226
+ ```python
227
+ # Single command
228
+ reply = await service.send_queue_command(
229
+ request=request,
230
+ machine_id="first",
231
+ run_id=run_id,
232
+ timeout=60 # Wait up to 60 seconds
233
+ )
234
+
235
+ # Multiple commands (timeout applies to each command)
236
+ reply = await service.send_queue_commands(
237
+ requests=commands,
238
+ machine_id="first",
239
+ run_id=run_id,
240
+ timeout=60 # Wait up to 60 seconds per command
241
+ )
242
+ ```
243
+
244
+ **Examples:**
245
+
246
+ See [`tests/commands.py`](tests/commands.py) for complete examples.
247
+
248
+ #### Immediate Commands
249
+
250
+ Immediate commands are control commands that interrupt or modify execution. Use `send_immediate_command()` for:
251
+ - `pause`: Pause the current execution
252
+ - `resume`: Resume a paused execution
253
+ - `cancel`: Cancel the current execution
254
+
255
+ **Examples:**
256
+
257
+ See [`tests/commands.py`](tests/commands.py) for complete examples.
258
+
259
+
260
+
261
+ ### Sending Command Sequences
262
+
263
+ You can send multiple commands in sequence using `send_queue_commands()`, which sends commands one by one and waits for each response before sending the next. If any command fails or times out, it stops immediately and returns the error response.
264
+
265
+ **Loading Commands from JSON (Recommended for LLM-generated commands):**
266
+
267
+ When generating commands from an LLM or loading from external sources, you can store commands in a JSON file and load them. See [`tests/batch_commands.py`](tests/batch_commands.py) for a complete example.
268
+
269
+ ### Error Handling
270
+
271
+ Always check the response status and handle errors appropriately:
272
+
273
+ ```python
274
+ reply: NATSMessage = await service.send_queue_command(
275
+ request=request,
276
+ machine_id="first",
277
+ run_id=run_id
278
+ )
279
+
280
+ if reply is None:
281
+ # Command timed out or failed to send
282
+ logger.error("Command failed or timed out")
283
+ elif reply.response is not None and reply.response.status == CommandResponseStatus.SUCCESS:
284
+ # Command succeeded
285
+ logger.info("Command completed successfully")
286
+ else:
287
+ # Command failed with error
288
+ logger.error("Command failed with code: %s, message: %s",
289
+ reply.response.code if reply.response else None,
290
+ reply.response.message if reply.response else None)
291
+ ```
292
+
293
+ ### Configuration
294
+
295
+ The `CommandService` reads NATS server URLs from the `NATS_SERVERS` environment variable, or defaults to:
296
+ ```
297
+ nats://192.168.50.201:4222,nats://192.168.50.201:4223,nats://192.168.50.201:4224
298
+ ```
299
+
300
+ You can also specify servers explicitly:
301
+ ```python
302
+ service = CommandService(servers=["nats://localhost:4222"])
303
+ ```
304
+ ## Validation
305
+
306
+ All models use Pydantic for validation, ensuring:
307
+ - Type checking for all fields
308
+ - Required fields are present
309
+ - Default values are applied correctly
310
+ - JSON serialization/deserialization works correctly
@@ -0,0 +1,298 @@
1
+ # Puda Comms
2
+
3
+ A Python module for communication between machines and command services via NATS messaging. Provides client-side services for sending commands, machine-side clients for receiving commands, and data models for structured message exchange.
4
+
5
+ ## Overview
6
+
7
+ The `puda_comms` module enables asynchronous, reliable communication between command services and machines using NATS (NATS JetStream for guaranteed delivery). It handles:
8
+
9
+ - **Command execution**: Send commands to machines and receive responses
10
+ - **Message routing**: Queue commands (sequential execution) and immediate commands (control operations)
11
+ - **State management**: Thread-safe execution state tracking for cancellation and locking
12
+ - **Connection management**: Automatic NATS connection handling with async context managers
13
+
14
+ ## Components
15
+
16
+ The module consists of four main components:
17
+
18
+ ### 1. Models (`models.py`)
19
+
20
+ Data models for structured message exchange. All models use Pydantic for validation and serialization.
21
+
22
+ #### Enums
23
+
24
+ ##### `CommandResponseStatus`
25
+ Status of a command response:
26
+ - `SUCCESS`: Command executed successfully
27
+ - `ERROR`: Command execution failed
28
+
29
+ ##### `CommandResponseCode`
30
+ Error codes for command responses:
31
+ - `COMMAND_CANCELLED`: Command was cancelled before completion
32
+ - `JSON_DECODE_ERROR`: Failed to decode JSON payload
33
+ - `EXECUTION_ERROR`: General execution error
34
+ - `EXECUTION_LOCKED`: Execution is locked (another command is running)
35
+ - `UNKNOWN_COMMAND`: Command name not recognized
36
+ - `PAUSE_ERROR`: Error occurred while pausing execution
37
+ - `RESUME_ERROR`: Error occurred while resuming execution
38
+ - `NO_EXECUTION`: No execution found
39
+ - `RUN_ID_MISMATCH`: Run ID doesn't match current execution
40
+ - `CANCEL_ERROR`: Error occurred while cancelling execution
41
+ - `MACHINE_PAUSED`: Machine is currently paused
42
+
43
+ ##### `MessageType`
44
+ Type of NATS message:
45
+ - `COMMAND`: Command message sent to machine
46
+ - `RESPONSE`: Response message from machine
47
+ - `LOG`: Log message
48
+ - `ALERT`: Alert message
49
+ - `MEDIA`: Media message
50
+
51
+ ##### `ImmediateCommand`
52
+ Command names for immediate/control commands:
53
+ - `PAUSE`: Pause the current execution
54
+ - `RESUME`: Resume a paused execution
55
+ - `CANCEL`: Cancel the current execution
56
+
57
+ #### Data Models
58
+
59
+ ##### `CommandRequest`
60
+ Represents a command to be sent to a machine.
61
+
62
+ **Fields:**
63
+ - `name` (str): The command name to execute
64
+ - `params` (Dict[str, Any]): Command parameters (default: empty dict)
65
+ - `step_number` (int): Execution step number for tracking progress
66
+ - `version` (str): Command version (default: "1.0")
67
+
68
+ **Example:**
69
+ ```python
70
+ command = CommandRequest(
71
+ name="attach_tip",
72
+ params={"slot": "A3", "well": "G8"},
73
+ step_number=2,
74
+ version="1.0"
75
+ )
76
+ ```
77
+
78
+ ##### `CommandResponse`
79
+ Represents the result of a command execution.
80
+
81
+ **Fields:**
82
+ - `status` (CommandResponseStatus): Status of the command response (SUCCESS or ERROR)
83
+ - `completed_at` (str): ISO 8601 UTC timestamp (auto-generated)
84
+ - `code` (Optional[str]): Error code if status is ERROR
85
+ - `message` (Optional[str]): Human-readable error message
86
+
87
+ **Example:**
88
+ ```python
89
+ response = CommandResponse(
90
+ status=CommandResponseStatus.SUCCESS,
91
+ completed_at="2026-01-20T02:00:46Z"
92
+ )
93
+ ```
94
+
95
+ **Error Example:**
96
+ ```python
97
+ error_response = CommandResponse(
98
+ status=CommandResponseStatus.ERROR,
99
+ code="EXECUTION_ERROR",
100
+ message="Failed to attach tip: slot A3 not found",
101
+ completed_at="2026-01-20T02:00:46Z"
102
+ )
103
+ ```
104
+
105
+ ##### `MessageHeader`
106
+ Header metadata for NATS messages.
107
+
108
+ **Fields:**
109
+ - `message_type` (MessageType): Type of message (COMMAND, RESPONSE, LOG, etc.)
110
+ - `version` (str): Message version (default: "1.0")
111
+ - `timestamp` (str): ISO 8601 UTC timestamp (auto-generated)
112
+ - `machine_id` (str): Identifier for the target machine
113
+ - `run_id` (Optional[str]): Unique identifier (UUID) for the run/workflow
114
+
115
+ **Example:**
116
+ ```python
117
+ header = MessageHeader(
118
+ message_type=MessageType.RESPONSE,
119
+ version="1.0",
120
+ timestamp="2026-01-20T02:00:46Z",
121
+ machine_id="first",
122
+ run_id="092073e6-13d0-4756-8d99-eff1612a5a72"
123
+ )
124
+ ```
125
+
126
+ ##### `NATSMessage`
127
+ Complete NATS message structure combining header with optional command or response data.
128
+
129
+ **Fields:**
130
+ - `header` (MessageHeader): Message header (required)
131
+ - `command` (Optional[CommandRequest]): Command request (for command messages)
132
+ - `response` (Optional[CommandResponse]): Command response (for response messages)
133
+
134
+ **Structure:**
135
+ - For command messages: include `header` with `message_type=COMMAND` and `command` field
136
+ - For response messages: include `header` with `message_type=RESPONSE` and `response` field
137
+
138
+ **Complete Message Example:**
139
+ ```json
140
+ {
141
+ "header": {
142
+ "message_type": "response",
143
+ "version": "1.0",
144
+ "timestamp": "2026-01-20T02:00:46Z",
145
+ "machine_id": "first",
146
+ "run_id": "092073e6-13d0-4756-8d99-eff1612a5a72"
147
+ },
148
+ "command": {
149
+ "name": "attach_tip",
150
+ "params": {
151
+ "slot": "A3",
152
+ "well": "G8"
153
+ },
154
+ "step_number": 2,
155
+ "version": "1.0"
156
+ },
157
+ "response": {
158
+ "status": "success",
159
+ "completed_at": "2026-01-20T02:00:46Z",
160
+ "code": null,
161
+ "message": null
162
+ }
163
+ }
164
+ ```
165
+
166
+ ### 2. CommandService (`command_service.py`)
167
+
168
+ Client-side service for sending commands to machines via NATS. Handles:
169
+ - Connecting to NATS servers
170
+ - Sending commands to machines (queue or immediate)
171
+ - Waiting for and handling responses
172
+ - Managing command lifecycle (run_id, step_number, etc.)
173
+ - Automatic connection cleanup via async context manager
174
+
175
+ See [Sending Commands](#sending-commands) section for usage examples.
176
+
177
+ ### 3. MachineClient (`machine_client.py`)
178
+
179
+ Basic default NATS client for generic machines. Handles commands, telemetry, and events following the `puda.{machine_id}.{category}.{sub_category}` pattern. Provides:
180
+ - Subscribing to command streams (queue and immediate) via JetStream with exactly-once delivery
181
+ - Processing incoming commands and sending command responses
182
+ - Publishing telemetry (core NATS, no JetStream)
183
+ - Publishing events (core NATS, fire-and-forget)
184
+ - Connection management and reconnection handling
185
+
186
+ **Note:** This is a generic client. Machine-specific methods should be implemented in the machine-edge client.
187
+
188
+ ### 4. ExecutionState (`execution_state.py`)
189
+
190
+ Thread-safe state management for command execution. Provides:
191
+ - Execution lock to prevent concurrent commands
192
+ - Current task tracking for cancellation
193
+ - Run ID matching for cancel operations
194
+ - Thread-safe access to execution state
195
+
196
+ ## Sending Commands
197
+
198
+ The `CommandService` provides a high-level interface for sending commands to machines via NATS. See [`tests/commands.py`](tests/commands.py) and [`tests/batch_commands.py`](tests/batch_commands.py) for complete examples.
199
+
200
+ ### Recommended Usage: Async Context Manager
201
+
202
+ The recommended way to use `CommandService` is with an async context manager, which automatically handles connection and disconnection. See [`tests/commands.py`](tests/commands.py) for complete examples.
203
+
204
+ ### Command Types
205
+
206
+ #### Queue Commands
207
+
208
+ Queue commands are regular commands that are executed in sequence. Use `send_queue_command()` for machine-specific operations.
209
+
210
+ **Note:** Available commands depend on the machine you are controlling. Different machines support different command sets. See [`puda_drivers`](../drivers/README.md) for information about available commands for each machine type (e.g., `first` machine supports commands like `load_deck`, `attach_tip`, `aspirate_from`, `dispense_to`, `drop_tip`, etc.).
211
+
212
+ Both `send_queue_command()`, `send_queue_commands()`, and `send_immediate_command()` accept an optional `timeout` parameter (default: 120 seconds):
213
+
214
+ ```python
215
+ # Single command
216
+ reply = await service.send_queue_command(
217
+ request=request,
218
+ machine_id="first",
219
+ run_id=run_id,
220
+ timeout=60 # Wait up to 60 seconds
221
+ )
222
+
223
+ # Multiple commands (timeout applies to each command)
224
+ reply = await service.send_queue_commands(
225
+ requests=commands,
226
+ machine_id="first",
227
+ run_id=run_id,
228
+ timeout=60 # Wait up to 60 seconds per command
229
+ )
230
+ ```
231
+
232
+ **Examples:**
233
+
234
+ See [`tests/commands.py`](tests/commands.py) for complete examples.
235
+
236
+ #### Immediate Commands
237
+
238
+ Immediate commands are control commands that interrupt or modify execution. Use `send_immediate_command()` for:
239
+ - `pause`: Pause the current execution
240
+ - `resume`: Resume a paused execution
241
+ - `cancel`: Cancel the current execution
242
+
243
+ **Examples:**
244
+
245
+ See [`tests/commands.py`](tests/commands.py) for complete examples.
246
+
247
+
248
+
249
+ ### Sending Command Sequences
250
+
251
+ You can send multiple commands in sequence using `send_queue_commands()`, which sends commands one by one and waits for each response before sending the next. If any command fails or times out, it stops immediately and returns the error response.
252
+
253
+ **Loading Commands from JSON (Recommended for LLM-generated commands):**
254
+
255
+ When generating commands from an LLM or loading from external sources, you can store commands in a JSON file and load them. See [`tests/batch_commands.py`](tests/batch_commands.py) for a complete example.
256
+
257
+ ### Error Handling
258
+
259
+ Always check the response status and handle errors appropriately:
260
+
261
+ ```python
262
+ reply: NATSMessage = await service.send_queue_command(
263
+ request=request,
264
+ machine_id="first",
265
+ run_id=run_id
266
+ )
267
+
268
+ if reply is None:
269
+ # Command timed out or failed to send
270
+ logger.error("Command failed or timed out")
271
+ elif reply.response is not None and reply.response.status == CommandResponseStatus.SUCCESS:
272
+ # Command succeeded
273
+ logger.info("Command completed successfully")
274
+ else:
275
+ # Command failed with error
276
+ logger.error("Command failed with code: %s, message: %s",
277
+ reply.response.code if reply.response else None,
278
+ reply.response.message if reply.response else None)
279
+ ```
280
+
281
+ ### Configuration
282
+
283
+ The `CommandService` reads NATS server URLs from the `NATS_SERVERS` environment variable, or defaults to:
284
+ ```
285
+ nats://192.168.50.201:4222,nats://192.168.50.201:4223,nats://192.168.50.201:4224
286
+ ```
287
+
288
+ You can also specify servers explicitly:
289
+ ```python
290
+ service = CommandService(servers=["nats://localhost:4222"])
291
+ ```
292
+ ## Validation
293
+
294
+ All models use Pydantic for validation, ensuring:
295
+ - Type checking for all fields
296
+ - Required fields are present
297
+ - Default values are applied correctly
298
+ - JSON serialization/deserialization works correctly
@@ -0,0 +1,22 @@
1
+ [project]
2
+ name = "puda-comms"
3
+ version = "0.0.2"
4
+ description = "Communication library for the PUDA platform."
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "zhao", email = "20024592+agentzhao@users.noreply.github.com" }
8
+ ]
9
+ requires-python = ">=3.14"
10
+ dependencies = [
11
+ "nats-py>=2.12.0",
12
+ # "puda-drivers>=0.0.16",
13
+ "puda-drivers",
14
+ "pydantic>=2.12.5",
15
+ ]
16
+
17
+ [tool.uv.sources]
18
+ puda-drivers = {workspace = true}
19
+
20
+ [build-system]
21
+ requires = ["uv_build>=0.9.18,<0.10.0"]
22
+ build-backend = "uv_build"
@@ -0,0 +1,5 @@
1
+ from .machine_client import MachineClient
2
+ from .execution_state import ExecutionState
3
+ from .command_service import CommandService
4
+
5
+ __all__ = ["MachineClient", "ExecutionState", "CommandService"]