pyromind-sdk 0.0.25__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 (49) hide show
  1. pyromind_sdk-0.0.25/LICENSE +22 -0
  2. pyromind_sdk-0.0.25/MANIFEST.in +9 -0
  3. pyromind_sdk-0.0.25/PKG-INFO +436 -0
  4. pyromind_sdk-0.0.25/README.md +397 -0
  5. pyromind_sdk-0.0.25/pyproject.toml +66 -0
  6. pyromind_sdk-0.0.25/pyromind_sdk/__init__.py +169 -0
  7. pyromind_sdk-0.0.25/pyromind_sdk/cli.py +89 -0
  8. pyromind_sdk-0.0.25/pyromind_sdk/client/__init__.py +53 -0
  9. pyromind_sdk-0.0.25/pyromind_sdk/client/async_base.py +459 -0
  10. pyromind_sdk-0.0.25/pyromind_sdk/client/async_client.py +111 -0
  11. pyromind_sdk-0.0.25/pyromind_sdk/client/async_echomind.py +140 -0
  12. pyromind_sdk-0.0.25/pyromind_sdk/client/async_inference.py +153 -0
  13. pyromind_sdk-0.0.25/pyromind_sdk/client/async_instance.py +211 -0
  14. pyromind_sdk-0.0.25/pyromind_sdk/client/async_sandbox.py +331 -0
  15. pyromind_sdk-0.0.25/pyromind_sdk/client/async_training.py +147 -0
  16. pyromind_sdk-0.0.25/pyromind_sdk/client/base.py +455 -0
  17. pyromind_sdk-0.0.25/pyromind_sdk/client/client.py +154 -0
  18. pyromind_sdk-0.0.25/pyromind_sdk/client/echomind.py +150 -0
  19. pyromind_sdk-0.0.25/pyromind_sdk/client/inference.py +187 -0
  20. pyromind_sdk-0.0.25/pyromind_sdk/client/instance.py +231 -0
  21. pyromind_sdk-0.0.25/pyromind_sdk/client/models.py +775 -0
  22. pyromind_sdk-0.0.25/pyromind_sdk/client/profile.py +89 -0
  23. pyromind_sdk-0.0.25/pyromind_sdk/client/sandbox.py +363 -0
  24. pyromind_sdk-0.0.25/pyromind_sdk/client/storage.py +727 -0
  25. pyromind_sdk-0.0.25/pyromind_sdk/client/training.py +232 -0
  26. pyromind_sdk-0.0.25/pyromind_sdk/client/workflow/__init__.py +55 -0
  27. pyromind_sdk-0.0.25/pyromind_sdk/client/workflow/converter.py +1242 -0
  28. pyromind_sdk-0.0.25/pyromind_sdk/client/workflow/validator.py +1880 -0
  29. pyromind_sdk-0.0.25/pyromind_sdk/common/__init__.py +16 -0
  30. pyromind_sdk-0.0.25/pyromind_sdk/common/constants.py +96 -0
  31. pyromind_sdk-0.0.25/pyromind_sdk/common/node_sdk.py +140 -0
  32. pyromind_sdk-0.0.25/pyromind_sdk/nodes/__init__.py +92 -0
  33. pyromind_sdk-0.0.25/pyromind_sdk/nodes/command_executor.py +747 -0
  34. pyromind_sdk-0.0.25/pyromind_sdk/nodes/function_call_wrapper.py +368 -0
  35. pyromind_sdk-0.0.25/pyromind_sdk/nodes/node_validator.py +150 -0
  36. pyromind_sdk-0.0.25/pyromind_sdk/nodes/python_function_executor.py +292 -0
  37. pyromind_sdk-0.0.25/pyromind_sdk/nodes/python_to_yaml.py +943 -0
  38. pyromind_sdk-0.0.25/pyromind_sdk/nodes/type_converter.py +126 -0
  39. pyromind_sdk-0.0.25/pyromind_sdk/nodes/yaml_loader.py +928 -0
  40. pyromind_sdk-0.0.25/pyromind_sdk/python_function_to_yaml_cli.py +73 -0
  41. pyromind_sdk-0.0.25/pyromind_sdk/tests/__init__.py +0 -0
  42. pyromind_sdk-0.0.25/pyromind_sdk/tests/test_yaml_nodes.py +337 -0
  43. pyromind_sdk-0.0.25/pyromind_sdk.egg-info/PKG-INFO +436 -0
  44. pyromind_sdk-0.0.25/pyromind_sdk.egg-info/SOURCES.txt +47 -0
  45. pyromind_sdk-0.0.25/pyromind_sdk.egg-info/dependency_links.txt +1 -0
  46. pyromind_sdk-0.0.25/pyromind_sdk.egg-info/requires.txt +10 -0
  47. pyromind_sdk-0.0.25/pyromind_sdk.egg-info/top_level.txt +1 -0
  48. pyromind_sdk-0.0.25/setup.cfg +4 -0
  49. pyromind_sdk-0.0.25/setup.py +52 -0
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 PyroMind Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,9 @@
1
+ include README.md
2
+ include LICENSE
3
+ include pyproject.toml
4
+ recursive-exclude * __pycache__
5
+ recursive-exclude * *.py[co]
6
+ # Exclude build and development files
7
+ exclude build_and_publish.sh
8
+ exclude update_version.py
9
+
@@ -0,0 +1,436 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyromind-sdk
3
+ Version: 0.0.25
4
+ Summary: Lightweight SDK stub for local development and testing of third-party nodes without the full platform codebase
5
+ Home-page: https://pyromind.ai/
6
+ Author: PyroMind Team
7
+ Author-email: PyroMind Team <support@pyromind.ai>
8
+ License-Expression: MIT
9
+ Project-URL: Homepage, https://pyromind.ai/
10
+ Project-URL: Documentation, https://github.com/pyromind/pyromind-sdk
11
+ Project-URL: Repository, https://github.com/pyromind/pyromind-sdk
12
+ Project-URL: Issues, https://github.com/pyromind/pyromind-sdk/issues
13
+ Keywords: sdk,node,development,stub,yaml,configuration
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: pyyaml>=6.0
27
+ Requires-Dist: requests>=2.28.0
28
+ Requires-Dist: pydantic>=2.0.0
29
+ Requires-Dist: urllib3>=1.26.0
30
+ Requires-Dist: minio>=7.0.0
31
+ Requires-Dist: aiohttp>=3.8.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: build; extra == "dev"
34
+ Requires-Dist: twine; extra == "dev"
35
+ Dynamic: author
36
+ Dynamic: home-page
37
+ Dynamic: license-file
38
+ Dynamic: requires-python
39
+
40
+ # PyroMind Node SDK
41
+
42
+ A lightweight SDK stub for local development and testing of third-party nodes without the full platform codebase (without `app.models.nodes`).
43
+
44
+ In the real platform runtime environment, nodes should prioritize importing base classes from `app.models.nodes`.
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ pip install pyromind-sdk
50
+ ```
51
+
52
+ ## Usage
53
+
54
+ ### YAML-based Node Configuration
55
+
56
+ Define nodes using YAML files with the unified `parameters` format. All inputs and outputs are defined in the `parameters` list:
57
+
58
+ - **Input parameters**: Use `type: "input"` with `required_type: "required"` or `"optional"`
59
+ - **Output parameters**: Use `type: "output"` (outputs are automatically extracted to create `RETURN_TYPES` and `RETURN_NAMES`)
60
+
61
+ ```python
62
+ from pyromind_sdk import load_nodes_from_yaml
63
+
64
+ # Load nodes from YAML file
65
+ nodes = load_nodes_from_yaml("my_node.yaml")
66
+ MyNode = nodes["MyNode"]
67
+
68
+ # Use the node class
69
+ print(MyNode.DESCRIPTION)
70
+ print(MyNode.BASE_INPUT_TYPES())
71
+ ```
72
+
73
+ #### Example YAML Node Configuration
74
+
75
+ Create `my_node.yaml`:
76
+
77
+ ```yaml
78
+ name: MyNode
79
+ description: "My custom node"
80
+ base_class: PodExecutionNode
81
+
82
+ command_template:
83
+ - "sh"
84
+ - "-c"
85
+ - "echo \"Hello, {{name}}!\" > {{output}}"
86
+
87
+ parameters:
88
+ - name: name
89
+ dtype: "STRING"
90
+ default: "World"
91
+ type: "input"
92
+ required_type: "required"
93
+ - name: output
94
+ dtype: "STRING"
95
+ type: "output"
96
+ ```
97
+
98
+ ## Main Classes
99
+
100
+ ### Base Node Classes
101
+
102
+ Base node classes are available for reference in YAML configurations. You can specify them in your YAML files using the `base_class` field:
103
+
104
+ - `PodExecutionNode`: Base class for Pod execution nodes
105
+ - `PortPodExecutionNode`: Pod execution node with port resource
106
+ - `DaemonPodExecutionNode`: Daemon Pod execution node
107
+ - `GpuPodExecutionNode`: GPU Pod execution node
108
+ - `JupyterLabPodExecutionNode`: Pod execution node with JupyterLab environment
109
+ - `EndpointNode`: Base class for endpoint nodes
110
+ - `NodeType`: Node type enumeration
111
+
112
+ These base classes are used internally by the YAML loader and should be referenced by name in your YAML configurations, not imported directly in Python code.
113
+
114
+ ### YAML Nodes Functions
115
+
116
+ - `load_nodes_from_yaml(yaml_path)`: Load nodes from a YAML file
117
+ - `load_all_nodes_from_directory(directory)`: Load all nodes from a directory
118
+ - `create_node_class_from_yaml(yaml_config, class_name)`: Create a node class from YAML config
119
+ - `yaml_to_node_class(yaml_path)`: Convert YAML config to Python class object
120
+
121
+ ### Python Function Nodes
122
+
123
+ You can also create nodes that execute Python functions directly:
124
+
125
+ ```yaml
126
+ name: CalculatorNode
127
+ description: "A calculator node using Python function"
128
+ base_class: PodExecutionNode
129
+
130
+ # Python function configuration
131
+ python_code: "utils/calculator.py" # Python file path (relative to YAML file or absolute path)
132
+ function_name: "calculate" # Function name
133
+
134
+ # Execution environment configuration (optional)
135
+ python_command: "python3" # Python execution command (default: python3)
136
+ # conda_env: "base" # Conda environment name (optional, default: "base")
137
+ # workdir: "/workspace/project" # Working directory (optional)
138
+ # environment: # Environment variables (optional)
139
+ # PYTHONUNBUFFERED: "1"
140
+
141
+ parameters:
142
+ - name: input0
143
+ type: input
144
+ dtype: FLOAT
145
+ required_type: required
146
+ default: 0.0
147
+ - name: input1
148
+ type: input
149
+ dtype: FLOAT
150
+ required_type: required
151
+ default: 0.0
152
+ - name: result_input0
153
+ type: output
154
+ dtype: STRING
155
+ - name: result_output0
156
+ type: output
157
+ dtype: STRING
158
+ ```
159
+
160
+ The corresponding Python function (`utils/calculator.py`):
161
+
162
+ ```python
163
+ def calculate(input0: float, input1: float) -> dict:
164
+ """Perform arithmetic operations"""
165
+ output0 = input0 + input1
166
+ return {
167
+ "result_input0": str(input0),
168
+ "result_output0": str(output0),
169
+ }
170
+ ```
171
+
172
+ ### Auto Generate: Python Function -> YAML
173
+
174
+ You can generate YAML config directly from a Python function signature and a return dict literal:
175
+
176
+ ```python
177
+ from pyromind_sdk import python_function_to_yaml
178
+
179
+ config = python_function_to_yaml(
180
+ python_file_path="pyromind_sdk/examples/nodes/utils/calculator.py",
181
+ function_name="calculate",
182
+ node_name="PythonCalculatorNode",
183
+ output_path="pyromind_sdk/examples/nodes/python_calculator_node.generated.yaml",
184
+ )
185
+ ```
186
+
187
+ Auto-generate rules:
188
+ - Inputs are generated from function parameters in order
189
+ - Input `dtype` is inferred from annotations (`str/int/float/bool`)
190
+ - Inputs are generated as `required_type: optional` with no default
191
+ - Outputs are generated only from `return { ... }` dict literals
192
+ - Return dict keys must be string literals
193
+ - Unknown types fall back to `STRING`
194
+ - Generated YAML `python_code` is emitted as an absolute path
195
+
196
+ CLI 用法(写入到 YAML 文件):
197
+
198
+ ```bash
199
+ python -m pyromind_sdk.cli python-to-yaml \
200
+ pyromind_sdk/examples/nodes/utils/calculator.py \
201
+ calculate \
202
+ --node-name PythonCalculatorNode \
203
+ --output pyromind_sdk/examples/nodes/python_calculator_node.generated.yaml
204
+ ```
205
+
206
+ 如果不传 `--output`,会把 YAML 直接打印到 stdout。
207
+
208
+
209
+ **Note on Python file paths:**
210
+ - Relative paths are resolved relative to the YAML file's directory
211
+ - Absolute paths are used as-is
212
+ - The Python file must exist and be accessible at the specified path
213
+
214
+ **Note on JupyterLab environment:**
215
+ - When using `JupyterLabPodExecutionNode`, the Python code will be executed in a JupyterLab environment
216
+ - Conda environment activation is handled automatically (default: `base` environment)
217
+ - The command execution uses `bash -c` with conda activation, so shell operators like `&&` are preserved
218
+
219
+ **Note on accelerate mode:**
220
+ - Accelerate mode is enabled only when `python_command: "accelerate"` (exact match after trimming spaces).
221
+ - Values that only start with `accelerate` (for example `accelerate launch --num_processes 2`) are treated as normal command strings.
222
+ - In accelerate mode, the node must inherit `GpuPodExecutionNode`.
223
+ - In accelerate mode, the SDK reads the input parameter with dtype `ACCELERATE_CONFIG`, writes it into `/tmp/accelerate_config_<uuid>.yaml`, and starts with `accelerate launch --config_file <tmp_file> ...`.
224
+ - `ACCELERATE_CONFIG` is injected by runtime automatically, so YAML does not need to declare it in `parameters`.
225
+
226
+ ## Advanced Features
227
+
228
+ ### Resource Configuration
229
+
230
+ Configure CPU, memory, and GPU resources:
231
+
232
+ ```yaml
233
+ resources:
234
+ memory_limit: 16 # Memory in GiB
235
+ cpu_limit: 4 # CPU cores
236
+ gpu_min_count: 1 # Minimum GPU count
237
+ gpu_max_count: 8 # Maximum GPU count
238
+ ```
239
+
240
+ ### Customer Inputs
241
+
242
+ Mark inputs/outputs for customer use (not used in command templates):
243
+
244
+ ```yaml
245
+ parameters:
246
+ - name: customer_param
247
+ type: input
248
+ dtype: STRING
249
+ required_type: required
250
+ customer_use: true # Mark as customer use
251
+ ```
252
+
253
+ ### Multiple Base Classes
254
+
255
+ Support for multiple inheritance. You can combine multiple base classes to meet your node's requirements:
256
+
257
+ ```yaml
258
+ base_class:
259
+ - GpuPodExecutionNode
260
+ - JupyterLabPodExecutionNode
261
+ ```
262
+
263
+ **When to use each base class:**
264
+
265
+ - **`PodExecutionNode`**: Basic Pod execution node (default). Use this for standard command execution without special requirements.
266
+
267
+ - **`GpuPodExecutionNode`**: **Required** if your node needs GPU resources. This base class provides GPU configuration options (`gpu_count`, `gpu_product`) and ensures GPU resources are allocated. If you specify GPU resources in the `resources` section or need GPU access, you must inherit from this class.
268
+
269
+ - **`JupyterLabPodExecutionNode`**: **Required** if your node needs to execute in a JupyterLab environment. Use this when you need interactive Python execution, notebook support, or Jupyter-specific features.
270
+
271
+ - **`PortPodExecutionNode`**: **Required** if your node needs port resources. This base class provides port configuration options for services that need to expose ports.
272
+
273
+ - **`DaemonPodExecutionNode`**: Use for daemon-style Pod execution nodes that run continuously in the background.
274
+
275
+ - **`EndpointNode`**: Use for nodes that return endpoint URLs. This base class automatically sets the return type to `STRING` with name `"endpoint"`.
276
+
277
+ **Examples:**
278
+
279
+ ```yaml
280
+ # Simple node without special requirements
281
+ base_class: PodExecutionNode
282
+
283
+ # GPU-enabled node
284
+ base_class: GpuPodExecutionNode
285
+
286
+ # GPU + JupyterLab environment
287
+ base_class:
288
+ - GpuPodExecutionNode
289
+ - JupyterLabPodExecutionNode
290
+
291
+ # Port resource node
292
+ base_class: PortPodExecutionNode
293
+ ```
294
+
295
+ ## API Reference
296
+
297
+ ### Core Functions
298
+
299
+ #### Loading Nodes
300
+
301
+ - `load_nodes_from_yaml(yaml_path: str) -> Dict[str, type]`: Load nodes from a YAML file
302
+ - `load_all_nodes_from_directory(directory: str) -> Dict[str, type]`: Load all nodes from a directory
303
+
304
+ #### Node Creation
305
+
306
+ - `create_node_class_from_yaml(yaml_config: Dict, class_name: str, yaml_file_path: Optional[str] = None) -> type`: Create a node class from YAML config
307
+
308
+ #### Conversion
309
+
310
+ - `yaml_to_node_class(yaml_path: str) -> type`: Convert YAML config to Python class object
311
+
312
+ ### Node Validation
313
+
314
+ - `validate_node_class(node_class: type, node_name: str) -> Dict[str, Any]`: Validate node class structure
315
+ - `print_node_info(node_name: str, node_class: type, validation: Dict, execution_result: Optional[Dict] = None)`: Print detailed node information
316
+
317
+ ### Command Execution
318
+
319
+ - `execute_command_template(command_template: List[str], inputs: Optional[Dict] = None, output_names: Optional[List[str]] = None, timeout: int = 300) -> Dict[str, Any]`: Execute command template
320
+
321
+ ### Type Conversion
322
+
323
+ - `convert_string_to_python_type(value: str, type_spec: Any) -> Any`: Convert string value to Python type
324
+ - `convert_inputs(inputs: Dict, input_types: Dict) -> Dict`: Convert input values according to type definitions
325
+ - `validate_output_type(value: Any, type_spec: str) -> bool`: Validate output value type
326
+
327
+ ### Workflow Functions
328
+
329
+ - `WorkflowLiteConverter`: Workflow lite format converter
330
+ - `LayoutGenerator`: Auto layout generator
331
+ - `to_workflow_lite(workflow: Dict) -> Dict`: Convert standard workflow to lite format
332
+ - `to_workflow_standard(workflow: Dict) -> Dict`: Convert lite workflow to standard format
333
+ - `validate_workflow(workflow: Dict, format: str = 'lite') -> ValidationResult`: Validate workflow format
334
+
335
+ ### Workflow Validation
336
+
337
+ - `validate_lite_format(workflow: Dict) -> ValidationResult`: Validate lite format workflow
338
+ - `validate_standard_format(workflow: Dict) -> ValidationResult`: Validate standard format workflow
339
+ - `validate_workflow_lite(workflow: Dict) -> ValidationResult`: Validate lite workflow
340
+ - `validate_workflow_standard(workflow: Dict) -> ValidationResult`: Validate standard workflow
341
+ - `validate_workflow_legacy(workflow: Dict) -> ValidationResult`: Validate legacy format workflow
342
+
343
+ ### Exception Classes
344
+
345
+ - `PyroMindAPIError`: API error exception
346
+ - `ValidationError`: Workflow validation error
347
+ - `SchemaValidationError`: Workflow schema validation error
348
+ - `LinkValidationError`: Workflow link validation error
349
+ - `TypeValidationError`: Workflow type validation error
350
+
351
+ ## Testing
352
+
353
+ Test your YAML node configurations:
354
+
355
+ ```bash
356
+ # Test a single YAML file
357
+ python -m pyromind_sdk.tests.test_yaml_nodes hello_world_node.yaml
358
+
359
+ # Test with verbose output
360
+ python -m pyromind_sdk.tests.test_yaml_nodes hello_world_node.yaml --verbose
361
+
362
+ # Execute the command template
363
+ python -m pyromind_sdk.tests.test_yaml_nodes hello_world_node.yaml --execute
364
+
365
+ # Test with custom inputs
366
+ python -m pyromind_sdk.tests.test_yaml_nodes hello_world_node.yaml --execute --inputs '{"name": "Alice"}'
367
+
368
+ # Test all YAML files in a directory
369
+ python -m pyromind_sdk.tests.test_yaml_nodes --directory examples
370
+ ```
371
+
372
+ ## Examples
373
+
374
+ Check the `examples/` directory for more examples:
375
+
376
+ - `hello_world_node.yaml`: Basic node example
377
+ - `echo_node.yaml`: Simple command execution
378
+ - `python_calculator_node.yaml`: Python function node with multiple inputs/outputs
379
+ - `jupyter_gpu_node.yaml`: Jupyter GPU execution example
380
+ - `accelerate_gpu_node.yaml`: Accelerate launch example for GPU Python nodes
381
+ - `multiline_text_node.yaml`: Multiline text processing
382
+ - `customer_inputs_node.yaml`: Customer inputs example
383
+
384
+ ## Features
385
+
386
+ - ✅ **Base Node Classes**: All standard node base classes for local development
387
+ - ✅ **YAML Configuration**: Define nodes using YAML files (Python class definitions are not supported)
388
+ - ✅ **Dynamic Loading**: Load nodes at runtime without code changes
389
+ - ✅ **Multiple Inheritance**: Support for multiple base classes in YAML
390
+ - ✅ **Python Function Nodes**: Execute Python functions directly in nodes via YAML configuration
391
+ - ✅ **Type Validation**: Automatic type conversion and validation
392
+ - ✅ **Resource Management**: Configure CPU, memory, and GPU resources
393
+ - ✅ **Customer Inputs**: Mark inputs/outputs for customer-specific use
394
+ - ✅ **Security**: Built-in validation and security checks
395
+ - ✅ **Workflow Conversion**: Support conversion between standard and lite formats
396
+ - ✅ **Workflow Validation**: Comprehensive workflow validation
397
+
398
+ ## Requirements
399
+
400
+ - Python >= 3.8
401
+ - pyyaml >= 6.0
402
+
403
+ ## Development
404
+
405
+ ### Project Structure
406
+
407
+ ```
408
+ pyromind_sdk/
409
+ ├── pyromind_sdk/
410
+ │ ├── common/ # Common utilities and base classes
411
+ │ ├── nodes/ # Node loading and execution
412
+ │ ├── examples/ # Example YAML configurations
413
+ │ └── tests/ # Test utilities
414
+ ├── setup.py
415
+ ├── pyproject.toml
416
+ └── README.md
417
+ ```
418
+
419
+ ### Contributing
420
+
421
+ Contributions are welcome! Please ensure:
422
+
423
+ 1. All code comments are in English
424
+ 2. Follow PEP 8 style guidelines
425
+ 3. Add tests for new features
426
+ 4. Update documentation as needed
427
+
428
+ ## License
429
+
430
+ MIT License
431
+
432
+ ## Links
433
+
434
+ - Website: https://pyromind.ai/
435
+ - PyPI: https://pypi.org/project/pyromind-sdk/
436
+ - Documentation: https://github.com/pyromind/pyromind-sdk