griptape-nodes 0.45.0__tar.gz → 0.46.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/PKG-INFO +1 -1
  2. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/pyproject.toml +1 -1
  3. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/__init__.py +51 -14
  4. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/node_library/workflow_registry.py +1 -1
  5. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/workflow_events.py +4 -2
  6. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/node_manager.py +1 -5
  7. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/version_compatibility_manager.py +84 -1
  8. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/workflow_manager.py +87 -3
  9. griptape_nodes-0.46.0/src/griptape_nodes/version_compatibility/workflow_versions/__init__.py +1 -0
  10. griptape_nodes-0.46.0/src/griptape_nodes/version_compatibility/workflow_versions/v0_7_0/__init__.py +1 -0
  11. griptape_nodes-0.46.0/src/griptape_nodes/version_compatibility/workflow_versions/v0_7_0/local_executor_argument_addition.py +42 -0
  12. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/README.md +0 -0
  13. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/app/.python-version +0 -0
  14. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/app/__init__.py +0 -0
  15. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/app/api.py +0 -0
  16. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/app/app.py +0 -0
  17. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/app/watch.py +0 -0
  18. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/bootstrap/__init__.py +0 -0
  19. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/bootstrap/workflow_executors/__init__.py +0 -0
  20. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py +0 -0
  21. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/bootstrap/workflow_executors/subprocess_workflow_executor.py +0 -0
  22. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/bootstrap/workflow_executors/workflow_executor.py +0 -0
  23. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/drivers/__init__.py +0 -0
  24. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/drivers/storage/__init__.py +0 -0
  25. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/drivers/storage/base_storage_driver.py +0 -0
  26. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +0 -0
  27. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/drivers/storage/local_storage_driver.py +0 -0
  28. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/drivers/storage/storage_backend.py +0 -0
  29. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/exe_types/__init__.py +0 -0
  30. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/exe_types/connections.py +0 -0
  31. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/exe_types/core_types.py +0 -0
  32. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/exe_types/flow.py +0 -0
  33. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/exe_types/node_types.py +0 -0
  34. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/exe_types/type_validator.py +0 -0
  35. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/machines/__init__.py +0 -0
  36. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/machines/control_flow.py +0 -0
  37. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/machines/fsm.py +0 -0
  38. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/machines/node_resolution.py +0 -0
  39. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/mcp_server/__init__.py +0 -0
  40. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/mcp_server/server.py +0 -0
  41. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/mcp_server/ws_request_manager.py +0 -0
  42. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/node_library/__init__.py +0 -0
  43. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/node_library/advanced_node_library.py +0 -0
  44. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/node_library/library_registry.py +0 -0
  45. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/py.typed +0 -0
  46. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/__init__.py +0 -0
  47. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/__init__.py +0 -0
  48. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/agent_events.py +0 -0
  49. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/app_events.py +0 -0
  50. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/arbitrary_python_events.py +0 -0
  51. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/base_events.py +0 -0
  52. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/config_events.py +0 -0
  53. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/connection_events.py +0 -0
  54. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/context_events.py +0 -0
  55. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/execution_events.py +0 -0
  56. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/flow_events.py +0 -0
  57. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/generate_request_payload_schemas.py +0 -0
  58. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/library_events.py +0 -0
  59. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/logger_events.py +0 -0
  60. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/node_events.py +0 -0
  61. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/object_events.py +0 -0
  62. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/os_events.py +0 -0
  63. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/parameter_events.py +0 -0
  64. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/payload_registry.py +0 -0
  65. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/secrets_events.py +0 -0
  66. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/static_file_events.py +0 -0
  67. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/sync_events.py +0 -0
  68. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/events/validation_events.py +0 -0
  69. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/griptape_nodes.py +0 -0
  70. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/__init__.py +0 -0
  71. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/agent_manager.py +0 -0
  72. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/arbitrary_code_exec_manager.py +0 -0
  73. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/config_manager.py +0 -0
  74. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/context_manager.py +0 -0
  75. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/engine_identity_manager.py +0 -0
  76. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/event_manager.py +0 -0
  77. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/flow_manager.py +0 -0
  78. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/__init__.py +0 -0
  79. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/data_models.py +0 -0
  80. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_directory.py +0 -0
  81. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_fsm.py +0 -0
  82. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/__init__.py +0 -0
  83. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/base.py +0 -0
  84. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/github.py +0 -0
  85. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/local_file.py +0 -0
  86. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/package.py +0 -0
  87. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/sandbox.py +0 -0
  88. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance.py +0 -0
  89. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_status.py +0 -0
  90. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/library_manager.py +0 -0
  91. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/object_manager.py +0 -0
  92. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/operation_manager.py +0 -0
  93. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/os_manager.py +0 -0
  94. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/secrets_manager.py +0 -0
  95. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/session_manager.py +0 -0
  96. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/settings.py +0 -0
  97. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/static_files_manager.py +0 -0
  98. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/managers/sync_manager.py +0 -0
  99. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/retained_mode.py +0 -0
  100. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/utils/__init__.py +0 -0
  101. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/utils/engine_identity.py +0 -0
  102. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/retained_mode/utils/name_generator.py +0 -0
  103. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/__init__.py +0 -0
  104. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/add_param_button.py +0 -0
  105. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/button.py +0 -0
  106. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/clamp.py +0 -0
  107. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/compare.py +0 -0
  108. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/compare_images.py +0 -0
  109. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/file_system_picker.py +0 -0
  110. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/minmax.py +0 -0
  111. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/options.py +0 -0
  112. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/slider.py +0 -0
  113. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/trait_registry.py +0 -0
  114. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/traits/traits.json +0 -0
  115. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/updater/__init__.py +0 -0
  116. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/updater/__main__.py +0 -0
  117. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/utils/__init__.py +0 -0
  118. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/utils/dict_utils.py +0 -0
  119. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/utils/image_preview.py +0 -0
  120. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/utils/metaclasses.py +0 -0
  121. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/utils/uv_utils.py +0 -0
  122. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/utils/version_utils.py +0 -0
  123. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/version_compatibility/__init__.py +0 -0
  124. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/version_compatibility/versions/__init__.py +0 -0
  125. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/version_compatibility/versions/v0_39_0/__init__.py +0 -0
  126. {griptape_nodes-0.45.0 → griptape_nodes-0.46.0}/src/griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_removal.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: griptape-nodes
3
- Version: 0.45.0
3
+ Version: 0.46.0
4
4
  Summary: Add your description here
5
5
  Requires-Dist: griptape>=1.8.0
6
6
  Requires-Dist: pydantic>=2.10.6
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "griptape-nodes"
3
- version = "0.45.0"
3
+ version = "0.46.0"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12.0, <3.13"
@@ -154,21 +154,23 @@ def _handle_storage_backend_config(config: InitConfig) -> str | None:
154
154
  return storage_backend
155
155
 
156
156
 
157
- def _handle_bucket_config(config: InitConfig, storage_backend: str | None) -> str | None:
158
- """Handle bucket configuration step (depends on API key and storage backend)."""
159
- storage_backend_bucket_id = None
157
+ def _handle_bucket_config(config: InitConfig) -> str | None:
158
+ """Handle bucket configuration step (depends on API key)."""
159
+ bucket_id = None
160
160
 
161
- if storage_backend == StorageBackend.GTC.value:
162
- if config.interactive:
163
- storage_backend_bucket_id = _prompt_for_gtc_bucket_name(default_bucket_name=config.bucket_name)
164
- elif config.bucket_name is not None:
165
- storage_backend_bucket_id = _get_or_create_bucket_id(config.bucket_name)
161
+ if config.interactive:
162
+ # First ask if they want to configure a bucket
163
+ configure_bucket = _prompt_for_bucket_configuration()
164
+ if configure_bucket:
165
+ bucket_id = _prompt_for_gtc_bucket_name(default_bucket_name=config.bucket_name)
166
+ elif config.bucket_name is not None:
167
+ bucket_id = _get_or_create_bucket_id(config.bucket_name)
166
168
 
167
- if storage_backend_bucket_id is not None:
168
- secrets_manager.set_secret("GT_CLOUD_BUCKET_ID", storage_backend_bucket_id)
169
- console.print(f"[bold green]Storage backend bucket ID set to: {storage_backend_bucket_id}[/bold green]")
169
+ if bucket_id is not None:
170
+ secrets_manager.set_secret("GT_CLOUD_BUCKET_ID", bucket_id)
171
+ console.print(f"[bold green]Bucket ID set to: {bucket_id}[/bold green]")
170
172
 
171
- return storage_backend_bucket_id
173
+ return bucket_id
172
174
 
173
175
 
174
176
  def _handle_advanced_library_config(config: InitConfig) -> bool | None:
@@ -211,9 +213,9 @@ def _run_init_configuration(config: InitConfig) -> None:
211
213
 
212
214
  _handle_workspace_config(config)
213
215
 
214
- storage_backend = _handle_storage_backend_config(config)
216
+ _handle_storage_backend_config(config)
215
217
 
216
- _handle_bucket_config(config, storage_backend)
218
+ _handle_bucket_config(config)
217
219
 
218
220
  _handle_advanced_library_config(config)
219
221
 
@@ -477,6 +479,41 @@ def _get_griptape_cloud_buckets_and_display_table() -> tuple[list[str], dict[str
477
479
  return bucket_names, name_to_id, table
478
480
 
479
481
 
482
+ def _prompt_for_bucket_configuration() -> bool:
483
+ """Prompts the user whether to configure a bucket for multi-machine workflow and asset syncing."""
484
+ # Check if there's already a bucket configured
485
+ current_bucket_id = secrets_manager.get_secret("GT_CLOUD_BUCKET_ID", should_error_on_not_found=False)
486
+
487
+ if current_bucket_id:
488
+ explainer = f"""[bold cyan]Griptape Cloud Bucket Configuration[/bold cyan]
489
+ You currently have a bucket configured (ID: {current_bucket_id}).
490
+
491
+ Buckets are used for multi-machine workflow and asset syncing, allowing you to:
492
+ - Share workflows and assets across multiple devices
493
+ - Sync generated content between different Griptape Nodes instances
494
+ - Access your work from anywhere
495
+
496
+ Would you like to change your selected bucket or keep the current one?"""
497
+ prompt_text = "Change selected Griptape Cloud bucket?"
498
+ default_value = False
499
+ else:
500
+ explainer = """[bold cyan]Griptape Cloud Bucket Configuration[/bold cyan]
501
+ Would you like to configure a Griptape Cloud bucket?
502
+ Buckets are used for multi-machine workflow and asset syncing, allowing you to:
503
+ - Share workflows and assets across multiple devices
504
+ - Sync generated content between different Griptape Nodes instances
505
+ - Access your work from anywhere
506
+
507
+ If you do not intend to use Griptape Nodes to collaborate or revision control your workflows, you can skip this step.
508
+
509
+ You can always configure a bucket later by running the initialization process again."""
510
+ prompt_text = "Configure Griptape Cloud bucket?"
511
+ default_value = False
512
+
513
+ console.print(Panel(explainer, expand=False))
514
+ return Confirm.ask(prompt_text, default=default_value)
515
+
516
+
480
517
  def _prompt_for_gtc_bucket_name(default_bucket_name: str | None = None) -> str:
481
518
  """Prompts the user for a GTC bucket and returns the bucket ID."""
482
519
  explainer = """[bold cyan]Storage Backend Bucket Selection[/bold cyan]
@@ -13,7 +13,7 @@ from griptape_nodes.utils.metaclasses import SingletonMeta
13
13
 
14
14
 
15
15
  class WorkflowMetadata(BaseModel):
16
- LATEST_SCHEMA_VERSION: ClassVar[str] = "0.6.1"
16
+ LATEST_SCHEMA_VERSION: ClassVar[str] = "0.7.0"
17
17
 
18
18
  name: str
19
19
  schema_version: str
@@ -31,7 +31,7 @@ class RunWorkflowFromScratchRequest(RequestPayload):
31
31
 
32
32
  @dataclass
33
33
  @PayloadRegistry.register
34
- class RunWorkflowFromScratchResultSuccess(WorkflowAlteredMixin, ResultPayloadSuccess):
34
+ class RunWorkflowFromScratchResultSuccess(ResultPayloadSuccess):
35
35
  """Workflow loaded and started successfully from file."""
36
36
 
37
37
 
@@ -91,7 +91,7 @@ class RunWorkflowFromRegistryRequest(RequestPayload):
91
91
 
92
92
  @dataclass
93
93
  @PayloadRegistry.register
94
- class RunWorkflowFromRegistryResultSuccess(WorkflowAlteredMixin, ResultPayloadSuccess):
94
+ class RunWorkflowFromRegistryResultSuccess(ResultPayloadSuccess):
95
95
  """Workflow from registry started successfully."""
96
96
 
97
97
 
@@ -347,6 +347,8 @@ class PublishWorkflowRequest(RequestPayload):
347
347
 
348
348
  workflow_name: str
349
349
  publisher_name: str
350
+ execute_on_publish: bool = False
351
+ published_workflow_file_name: str | None = None
350
352
 
351
353
 
352
354
  @dataclass
@@ -1480,11 +1480,7 @@ class NodeManager:
1480
1480
  return SetParameterValueResultFailure()
1481
1481
  if request.initial_setup is False and not request.is_output and modified:
1482
1482
  # Mark node as unresolved, broadcast an event
1483
- node.make_node_unresolved(
1484
- current_states_to_trigger_change_event=set(
1485
- {NodeResolutionState.RESOLVED, NodeResolutionState.RESOLVING}
1486
- )
1487
- )
1483
+ node.make_node_unresolved(current_states_to_trigger_change_event=set({NodeResolutionState.RESOLVED}))
1488
1484
  # Get the flow
1489
1485
  # Pass the value through!
1490
1486
  # Optional data_type parameter for internal handling!
@@ -14,8 +14,10 @@ from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes, Version
14
14
 
15
15
  if TYPE_CHECKING:
16
16
  from griptape_nodes.node_library.library_registry import LibrarySchema
17
+ from griptape_nodes.node_library.workflow_registry import WorkflowMetadata
17
18
  from griptape_nodes.retained_mode.managers.event_manager import EventManager
18
19
  from griptape_nodes.retained_mode.managers.library_lifecycle.library_status import LibraryStatus
20
+ from griptape_nodes.retained_mode.managers.workflow_manager import WorkflowManager
19
21
 
20
22
  logger = logging.getLogger("griptape_nodes")
21
23
 
@@ -39,16 +41,41 @@ class LibraryVersionCompatibilityCheck(ABC):
39
41
  """Perform the library compatibility check."""
40
42
 
41
43
 
44
+ class WorkflowVersionCompatibilityIssue(NamedTuple):
45
+ """Represents a workflow version compatibility issue found in a workflow."""
46
+
47
+ message: str
48
+ severity: WorkflowManager.WorkflowStatus
49
+
50
+
51
+ class WorkflowVersionCompatibilityCheck(ABC):
52
+ """Abstract base class for workflow version compatibility checks."""
53
+
54
+ @abstractmethod
55
+ def applies_to_workflow(self, workflow_metadata: WorkflowMetadata) -> bool:
56
+ """Return True if this check applies to the given workflow."""
57
+
58
+ @abstractmethod
59
+ def check_workflow(self, workflow_metadata: WorkflowMetadata) -> list[WorkflowVersionCompatibilityIssue]:
60
+ """Perform the workflow compatibility check."""
61
+
62
+
42
63
  class VersionCompatibilityManager:
43
64
  """Manages version compatibility checks for libraries and other components."""
44
65
 
45
66
  def __init__(self, event_manager: EventManager) -> None:
46
67
  self._event_manager = event_manager
47
68
  self._compatibility_checks: list[LibraryVersionCompatibilityCheck] = []
69
+ self._workflow_compatibility_checks: list[WorkflowVersionCompatibilityCheck] = []
48
70
  self._discover_version_checks()
49
71
 
50
72
  def _discover_version_checks(self) -> None:
51
- """Automatically discover and register library version compatibility checks."""
73
+ """Automatically discover and register library and workflow version compatibility checks."""
74
+ self._discover_library_version_checks()
75
+ self._discover_workflow_version_checks()
76
+
77
+ def _discover_library_version_checks(self) -> None:
78
+ """Discover and register library version compatibility checks."""
52
79
  # Get the path to the version_compatibility/versions directory
53
80
  import griptape_nodes.version_compatibility.versions as versions_module
54
81
 
@@ -59,6 +86,21 @@ class VersionCompatibilityManager:
59
86
  if version_dir.is_dir() and not version_dir.name.startswith("__"):
60
87
  self._discover_checks_in_version_dir(version_dir)
61
88
 
89
+ def _discover_workflow_version_checks(self) -> None:
90
+ """Discover and register workflow version compatibility checks."""
91
+ try:
92
+ import griptape_nodes.version_compatibility.workflow_versions as workflow_versions_module
93
+
94
+ workflow_versions_path = Path(workflow_versions_module.__file__).parent
95
+
96
+ # Iterate through version directories
97
+ for version_dir in workflow_versions_path.iterdir():
98
+ if version_dir.is_dir() and not version_dir.name.startswith("__"):
99
+ self._discover_workflow_checks_in_version_dir(version_dir)
100
+ except ImportError:
101
+ # workflow_versions directory doesn't exist yet, skip discovery
102
+ logger.debug("No workflow version compatibility checks directory found, skipping workflow check discovery")
103
+
62
104
  def _discover_checks_in_version_dir(self, version_dir: Path) -> None:
63
105
  """Discover compatibility checks in a specific version directory."""
64
106
  # Iterate through Python files in the version directory
@@ -82,6 +124,33 @@ class VersionCompatibilityManager:
82
124
  self._compatibility_checks.append(check_instance)
83
125
  logger.debug("Registered library version compatibility check: %s", attr_name)
84
126
 
127
+ def _discover_workflow_checks_in_version_dir(self, version_dir: Path) -> None:
128
+ """Discover workflow compatibility checks in a specific version directory."""
129
+ # Iterate through Python files in the version directory
130
+ for check_file in version_dir.glob("*.py"):
131
+ if check_file.name.startswith("__"):
132
+ continue
133
+
134
+ # Import the module
135
+ module_path = f"griptape_nodes.version_compatibility.workflow_versions.{version_dir.name}.{check_file.stem}"
136
+ try:
137
+ module = importlib.import_module(module_path)
138
+ except ImportError as e:
139
+ logger.debug("Failed to import workflow compatibility check module %s: %s", module_path, e)
140
+ continue
141
+
142
+ # Look for classes that inherit from WorkflowVersionCompatibilityCheck
143
+ for attr_name in dir(module):
144
+ attr = getattr(module, attr_name)
145
+ if (
146
+ isinstance(attr, type)
147
+ and issubclass(attr, WorkflowVersionCompatibilityCheck)
148
+ and attr is not WorkflowVersionCompatibilityCheck
149
+ ):
150
+ check_instance = attr()
151
+ self._workflow_compatibility_checks.append(check_instance)
152
+ logger.debug("Registered workflow version compatibility check: %s", attr_name)
153
+
85
154
  def check_library_version_compatibility(
86
155
  self, library_data: LibrarySchema
87
156
  ) -> list[LibraryVersionCompatibilityIssue]:
@@ -96,6 +165,20 @@ class VersionCompatibilityManager:
96
165
 
97
166
  return version_issues
98
167
 
168
+ def check_workflow_version_compatibility(
169
+ self, workflow_metadata: WorkflowMetadata
170
+ ) -> list[WorkflowVersionCompatibilityIssue]:
171
+ """Check a workflow for version compatibility issues."""
172
+ version_issues = []
173
+
174
+ # Run all discovered workflow compatibility checks
175
+ for check_instance in self._workflow_compatibility_checks:
176
+ if check_instance.applies_to_workflow(workflow_metadata):
177
+ issues = check_instance.check_workflow(workflow_metadata)
178
+ version_issues.extend(issues)
179
+
180
+ return version_issues
181
+
99
182
  def _get_current_engine_version(self) -> Version:
100
183
  """Get the current engine version."""
101
184
  result = GriptapeNodes.handle_request(GetEngineVersionRequest())
@@ -959,6 +959,16 @@ class WorkflowManager:
959
959
  status=status,
960
960
  )
961
961
  )
962
+
963
+ # Check for workflow version-based compatibility issues and add to problems
964
+ workflow_version_issues = GriptapeNodes.VersionCompatibilityManager().check_workflow_version_compatibility(
965
+ workflow_metadata
966
+ )
967
+ for issue in workflow_version_issues:
968
+ problems.append(issue.message)
969
+ if issue.severity == WorkflowManager.WorkflowStatus.UNUSABLE:
970
+ had_critical_error = True
971
+
962
972
  # OK, we have all of our dependencies together. Let's look at the overall scenario.
963
973
  if had_critical_error:
964
974
  overall_status = WorkflowManager.WorkflowStatus.UNUSABLE
@@ -1490,6 +1500,7 @@ class WorkflowManager:
1490
1500
 
1491
1501
  # === imports ===
1492
1502
  import_recorder.add_import("argparse")
1503
+ import_recorder.add_import("json")
1493
1504
  import_recorder.add_from_import(
1494
1505
  "griptape_nodes.bootstrap.workflow_executors.local_workflow_executor", "LocalWorkflowExecutor"
1495
1506
  )
@@ -1629,6 +1640,29 @@ class WorkflowManager:
1629
1640
  )
1630
1641
  )
1631
1642
 
1643
+ # Add json input argument
1644
+ add_arg_calls.append(
1645
+ ast.Expr(
1646
+ value=ast.Call(
1647
+ func=ast.Attribute(
1648
+ value=ast.Name(id="parser", ctx=ast.Load()),
1649
+ attr="add_argument",
1650
+ ctx=ast.Load(),
1651
+ ),
1652
+ args=[ast.Constant("--json-input")],
1653
+ keywords=[
1654
+ ast.keyword(arg="default", value=ast.Constant(None)),
1655
+ ast.keyword(
1656
+ arg="help",
1657
+ value=ast.Constant(
1658
+ "JSON string containing parameter values. Takes precedence over individual parameter arguments if provided."
1659
+ ),
1660
+ ),
1661
+ ],
1662
+ )
1663
+ )
1664
+ )
1665
+
1632
1666
  # Generate individual arguments for each parameter in workflow_shape["input"]
1633
1667
  if "input" in workflow_shape:
1634
1668
  for node_name, node_params in workflow_shape["input"].items():
@@ -1670,13 +1704,47 @@ class WorkflowManager:
1670
1704
  ),
1671
1705
  )
1672
1706
 
1673
- # Build flow_input dictionary from individual CLI arguments
1707
+ # Build flow_input dictionary from JSON input or individual CLI arguments
1674
1708
  flow_input_init = ast.Assign(
1675
1709
  targets=[ast.Name(id="flow_input", ctx=ast.Store())],
1676
1710
  value=ast.Dict(keys=[], values=[]),
1677
1711
  )
1678
1712
 
1679
- # Build the flow_input dict structure from individual arguments
1713
+ # Check if json_input is provided and parse it
1714
+ json_input_if = ast.If(
1715
+ test=ast.Compare(
1716
+ left=ast.Attribute(
1717
+ value=ast.Name(id="args", ctx=ast.Load()),
1718
+ attr="json_input",
1719
+ ctx=ast.Load(),
1720
+ ),
1721
+ ops=[ast.IsNot()],
1722
+ comparators=[ast.Constant(value=None)],
1723
+ ),
1724
+ body=[
1725
+ ast.Assign(
1726
+ targets=[ast.Name(id="flow_input", ctx=ast.Store())],
1727
+ value=ast.Call(
1728
+ func=ast.Attribute(
1729
+ value=ast.Name(id="json", ctx=ast.Load()),
1730
+ attr="loads",
1731
+ ctx=ast.Load(),
1732
+ ),
1733
+ args=[
1734
+ ast.Attribute(
1735
+ value=ast.Name(id="args", ctx=ast.Load()),
1736
+ attr="json_input",
1737
+ ctx=ast.Load(),
1738
+ )
1739
+ ],
1740
+ keywords=[],
1741
+ ),
1742
+ )
1743
+ ],
1744
+ orelse=[],
1745
+ )
1746
+
1747
+ # Build the flow_input dict structure from individual arguments (fallback when no JSON input)
1680
1748
  build_flow_input_stmts = []
1681
1749
 
1682
1750
  # For each node, ensure it exists in flow_input
@@ -1747,6 +1815,21 @@ class WorkflowManager:
1747
1815
  ]
1748
1816
  )
1749
1817
 
1818
+ # Wrap the individual argument processing in an else clause
1819
+ individual_args_else = ast.If(
1820
+ test=ast.Compare(
1821
+ left=ast.Attribute(
1822
+ value=ast.Name(id="args", ctx=ast.Load()),
1823
+ attr="json_input",
1824
+ ctx=ast.Load(),
1825
+ ),
1826
+ ops=[ast.Is()],
1827
+ comparators=[ast.Constant(value=None)],
1828
+ ),
1829
+ body=build_flow_input_stmts,
1830
+ orelse=[],
1831
+ )
1832
+
1750
1833
  workflow_output = ast.Assign(
1751
1834
  targets=[ast.Name(id="workflow_output", ctx=ast.Store())],
1752
1835
  value=ast.Call(
@@ -1780,7 +1863,8 @@ class WorkflowManager:
1780
1863
  *add_arg_calls,
1781
1864
  parse_args,
1782
1865
  flow_input_init,
1783
- *build_flow_input_stmts,
1866
+ json_input_if,
1867
+ individual_args_else,
1784
1868
  workflow_output,
1785
1869
  print_output,
1786
1870
  ],
@@ -0,0 +1 @@
1
+ """Workflow version compatibility checks module."""
@@ -0,0 +1 @@
1
+ """Version 0.7.0 workflow compatibility checks."""
@@ -0,0 +1,42 @@
1
+ """Schema compatibility check for workflows."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from griptape_nodes.retained_mode.griptape_nodes import Version
8
+ from griptape_nodes.retained_mode.managers.version_compatibility_manager import (
9
+ WorkflowVersionCompatibilityCheck,
10
+ WorkflowVersionCompatibilityIssue,
11
+ )
12
+ from griptape_nodes.retained_mode.managers.workflow_manager import WorkflowManager
13
+
14
+ if TYPE_CHECKING:
15
+ from griptape_nodes.node_library.workflow_registry import WorkflowMetadata
16
+
17
+
18
+ class LocalExecutorArgumentAddition(WorkflowVersionCompatibilityCheck):
19
+ """Check for workflow schema version compatibility issues due to missing `--json-input` argument in LocalExecutor."""
20
+
21
+ def applies_to_workflow(self, workflow_metadata: WorkflowMetadata) -> bool:
22
+ """Apply this check to workflows with schema version < 0.7.0."""
23
+ workflow_version = Version.from_string(workflow_metadata.schema_version)
24
+ return workflow_version is not None and workflow_version < Version(0, 7, 0)
25
+
26
+ def check_workflow(self, workflow_metadata: WorkflowMetadata) -> list[WorkflowVersionCompatibilityIssue]:
27
+ """Check workflow schema version compatibility."""
28
+ issues = []
29
+
30
+ workflow_schema_version = Version.from_string(workflow_metadata.schema_version)
31
+
32
+ if workflow_schema_version is not None and workflow_schema_version < Version(0, 7, 0):
33
+ issues.append(
34
+ WorkflowVersionCompatibilityIssue(
35
+ message=f"Workflow schema version {workflow_metadata.schema_version} is older than version 0.7.0. "
36
+ "The generated LocalExecutor code for the workflow file is missing the `--json-input` argument, which may cause issues for Publish Workflow requests when using certain Library targets. "
37
+ "Consider updating the workflow by saving it again.",
38
+ severity=WorkflowManager.WorkflowStatus.FLAWED,
39
+ )
40
+ )
41
+
42
+ return issues