griptape-nodes 0.62.2__py3-none-any.whl → 0.63.0__py3-none-any.whl
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.
- griptape_nodes/cli/commands/libraries.py +6 -21
- griptape_nodes/drivers/thread_storage/__init__.py +15 -0
- griptape_nodes/drivers/thread_storage/base_thread_storage_driver.py +106 -0
- griptape_nodes/drivers/thread_storage/griptape_cloud_thread_storage_driver.py +213 -0
- griptape_nodes/drivers/thread_storage/local_thread_storage_driver.py +137 -0
- griptape_nodes/drivers/thread_storage/thread_storage_backend.py +10 -0
- griptape_nodes/node_library/library_registry.py +16 -9
- griptape_nodes/node_library/workflow_registry.py +1 -1
- griptape_nodes/retained_mode/events/agent_events.py +232 -9
- griptape_nodes/retained_mode/events/app_events.py +38 -0
- griptape_nodes/retained_mode/events/library_events.py +32 -3
- griptape_nodes/retained_mode/events/os_events.py +101 -1
- griptape_nodes/retained_mode/managers/agent_manager.py +335 -135
- griptape_nodes/retained_mode/managers/fitness_problems/__init__.py +1 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/__init__.py +59 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/advanced_library_load_failure_problem.py +33 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/after_library_callback_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/before_library_callback_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/create_config_category_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/dependency_installation_failed_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/deprecated_node_warning_problem.py +83 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/duplicate_library_problem.py +28 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/duplicate_node_registration_problem.py +44 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/engine_version_error_problem.py +28 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/insufficient_disk_space_problem.py +33 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/invalid_version_string_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_json_decode_problem.py +28 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_load_exception_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_not_found_problem.py +30 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_problem.py +20 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_schema_exception_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/library_schema_validation_problem.py +38 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/modified_parameters_set_deprecation_warning_problem.py +44 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/modified_parameters_set_removed_problem.py +44 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/node_class_not_base_node_problem.py +40 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/node_class_not_found_problem.py +38 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/node_module_import_problem.py +53 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/sandbox_directory_missing_problem.py +28 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/ui_options_field_modified_incompatible_problem.py +44 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/ui_options_field_modified_warning_problem.py +35 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/update_config_category_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/venv_creation_failed_problem.py +32 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/__init__.py +75 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/deprecated_node_in_workflow_problem.py +83 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_dependency_version_string_problem.py +38 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_library_version_string_problem.py +38 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_metadata_schema_problem.py +31 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_metadata_section_count_problem.py +31 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/invalid_toml_format_problem.py +30 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_not_registered_problem.py +35 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_below_required_problem.py +41 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_large_difference_problem.py +41 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_major_mismatch_problem.py +41 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/library_version_minor_difference_problem.py +41 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/missing_creation_date_problem.py +30 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/missing_last_modified_date_problem.py +30 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/missing_toml_section_problem.py +30 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/node_type_not_found_problem.py +51 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/workflow_not_found_problem.py +27 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/workflow_problem.py +20 -0
- griptape_nodes/retained_mode/managers/fitness_problems/workflows/workflow_schema_version_problem.py +39 -0
- griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/local_file.py +17 -3
- griptape_nodes/retained_mode/managers/library_manager.py +226 -77
- griptape_nodes/retained_mode/managers/os_manager.py +172 -1
- griptape_nodes/retained_mode/managers/settings.py +5 -0
- griptape_nodes/retained_mode/managers/version_compatibility_manager.py +76 -51
- griptape_nodes/retained_mode/managers/workflow_manager.py +237 -159
- griptape_nodes/servers/static.py +18 -19
- griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_removal.py +16 -12
- griptape_nodes/version_compatibility/workflow_versions/v0_7_0/local_executor_argument_addition.py +6 -3
- {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/METADATA +2 -1
- {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/RECORD +74 -21
- {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/WHEEL +0 -0
- {griptape_nodes-0.62.2.dist-info → griptape_nodes-0.63.0.dist-info}/entry_points.txt +0 -0
|
@@ -5,6 +5,7 @@ import asyncio
|
|
|
5
5
|
import logging
|
|
6
6
|
import pickle
|
|
7
7
|
import re
|
|
8
|
+
from collections import defaultdict
|
|
8
9
|
from dataclasses import dataclass, field, fields, is_dataclass
|
|
9
10
|
from datetime import UTC, datetime
|
|
10
11
|
from enum import StrEnum
|
|
@@ -32,12 +33,15 @@ from griptape_nodes.node_library.workflow_registry import (
|
|
|
32
33
|
WorkflowShape,
|
|
33
34
|
)
|
|
34
35
|
from griptape_nodes.retained_mode.events.app_events import (
|
|
36
|
+
EngineInitializationProgress,
|
|
35
37
|
GetEngineVersionRequest,
|
|
36
38
|
GetEngineVersionResultSuccess,
|
|
39
|
+
InitializationPhase,
|
|
40
|
+
InitializationStatus,
|
|
37
41
|
)
|
|
38
42
|
|
|
39
43
|
# Runtime imports for ResultDetails since it's used at runtime
|
|
40
|
-
from griptape_nodes.retained_mode.events.base_events import ResultDetail, ResultDetails
|
|
44
|
+
from griptape_nodes.retained_mode.events.base_events import AppEvent, ResultDetail, ResultDetails
|
|
41
45
|
from griptape_nodes.retained_mode.events.flow_events import (
|
|
42
46
|
CreateFlowRequest,
|
|
43
47
|
GetTopLevelFlowRequest,
|
|
@@ -51,6 +55,8 @@ from griptape_nodes.retained_mode.events.flow_events import (
|
|
|
51
55
|
from griptape_nodes.retained_mode.events.library_events import (
|
|
52
56
|
GetLibraryMetadataRequest,
|
|
53
57
|
GetLibraryMetadataResultSuccess,
|
|
58
|
+
ListRegisteredLibrariesRequest,
|
|
59
|
+
ListRegisteredLibrariesResultSuccess,
|
|
54
60
|
)
|
|
55
61
|
from griptape_nodes.retained_mode.events.object_events import ClearAllObjectStateRequest
|
|
56
62
|
from griptape_nodes.retained_mode.events.workflow_events import (
|
|
@@ -115,6 +121,22 @@ from griptape_nodes.retained_mode.events.workflow_events import (
|
|
|
115
121
|
from griptape_nodes.retained_mode.griptape_nodes import (
|
|
116
122
|
GriptapeNodes,
|
|
117
123
|
)
|
|
124
|
+
from griptape_nodes.retained_mode.managers.fitness_problems.workflows import (
|
|
125
|
+
InvalidDependencyVersionStringProblem,
|
|
126
|
+
InvalidLibraryVersionStringProblem,
|
|
127
|
+
InvalidMetadataSchemaProblem,
|
|
128
|
+
InvalidMetadataSectionCountProblem,
|
|
129
|
+
InvalidTomlFormatProblem,
|
|
130
|
+
LibraryNotRegisteredProblem,
|
|
131
|
+
LibraryVersionBelowRequiredProblem,
|
|
132
|
+
LibraryVersionLargeDifferenceProblem,
|
|
133
|
+
LibraryVersionMajorMismatchProblem,
|
|
134
|
+
LibraryVersionMinorDifferenceProblem,
|
|
135
|
+
MissingCreationDateProblem,
|
|
136
|
+
MissingLastModifiedDateProblem,
|
|
137
|
+
MissingTomlSectionProblem,
|
|
138
|
+
WorkflowNotFoundProblem,
|
|
139
|
+
)
|
|
118
140
|
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
119
141
|
|
|
120
142
|
if TYPE_CHECKING:
|
|
@@ -125,6 +147,7 @@ if TYPE_CHECKING:
|
|
|
125
147
|
from griptape_nodes.retained_mode.events.base_events import ResultPayload
|
|
126
148
|
from griptape_nodes.retained_mode.events.node_events import SerializedNodeCommands, SetLockNodeStateRequest
|
|
127
149
|
from griptape_nodes.retained_mode.managers.event_manager import EventManager
|
|
150
|
+
from griptape_nodes.retained_mode.managers.fitness_problems.workflows.workflow_problem import WorkflowProblem
|
|
128
151
|
|
|
129
152
|
|
|
130
153
|
T = TypeVar("T")
|
|
@@ -186,7 +209,7 @@ class WorkflowManager:
|
|
|
186
209
|
workflow_path: str
|
|
187
210
|
workflow_name: str | None = None
|
|
188
211
|
workflow_dependencies: list[WorkflowManager.WorkflowDependencyInfo] = field(default_factory=list)
|
|
189
|
-
problems: list[
|
|
212
|
+
problems: list[WorkflowProblem] = field(default_factory=list)
|
|
190
213
|
|
|
191
214
|
_workflow_file_path_to_info: dict[str, WorkflowInfo]
|
|
192
215
|
|
|
@@ -416,30 +439,48 @@ class WorkflowManager:
|
|
|
416
439
|
|
|
417
440
|
return matches
|
|
418
441
|
|
|
419
|
-
def print_workflow_load_status(self) -> None:
|
|
442
|
+
def print_workflow_load_status(self, min_status: WorkflowStatus = WorkflowStatus.FLAWED) -> None: # noqa: PLR0915
|
|
420
443
|
workflow_file_paths = self.get_workflows_attempted_to_load()
|
|
421
444
|
workflow_infos = []
|
|
422
445
|
for workflow_file_path in workflow_file_paths:
|
|
423
446
|
workflow_info = self.get_workflow_info_for_attempted_load(workflow_file_path)
|
|
424
447
|
workflow_infos.append(workflow_info)
|
|
425
448
|
|
|
449
|
+
# Filter workflows to only show those at or worse than min_status
|
|
450
|
+
all_statuses = list(self.WorkflowStatus)
|
|
451
|
+
min_status_index = all_statuses.index(min_status)
|
|
452
|
+
filtered_workflow_infos = [
|
|
453
|
+
wf_info for wf_info in workflow_infos if all_statuses.index(wf_info.status) >= min_status_index
|
|
454
|
+
]
|
|
455
|
+
|
|
456
|
+
# Sort workflows by severity (worst to best)
|
|
457
|
+
filtered_workflow_infos.sort(key=lambda wf: all_statuses.index(wf.status), reverse=True)
|
|
458
|
+
|
|
426
459
|
console = Console()
|
|
427
460
|
|
|
428
461
|
# Check if the list is empty
|
|
429
|
-
if not
|
|
430
|
-
# Display a message indicating no workflows are available
|
|
462
|
+
if not filtered_workflow_infos:
|
|
431
463
|
empty_message = Text("No workflow information available", style="italic")
|
|
432
464
|
panel = Panel(empty_message, title="Workflow Information", border_style="blue")
|
|
433
465
|
console.print(panel)
|
|
434
466
|
return
|
|
435
467
|
|
|
436
|
-
#
|
|
468
|
+
# Add filter message if not showing all workflows
|
|
469
|
+
if min_status != self.WorkflowStatus.GOOD:
|
|
470
|
+
statuses_shown = all_statuses[min_status_index:]
|
|
471
|
+
status_names = ", ".join(s.value for s in statuses_shown)
|
|
472
|
+
filter_message = Text(
|
|
473
|
+
f"Only displaying workflows with a fitness of {status_names}",
|
|
474
|
+
style="italic yellow",
|
|
475
|
+
)
|
|
476
|
+
console.print(filter_message)
|
|
477
|
+
console.print()
|
|
478
|
+
|
|
479
|
+
# Create a table with three columns and row dividers
|
|
437
480
|
table = Table(show_header=True, box=HEAVY_EDGE, show_lines=True, expand=True)
|
|
438
|
-
table.add_column("Workflow
|
|
439
|
-
table.add_column("
|
|
440
|
-
table.add_column("
|
|
441
|
-
table.add_column("Problems", style="yellow")
|
|
442
|
-
table.add_column("Dependencies", style="magenta")
|
|
481
|
+
table.add_column("Workflow", style="green", ratio=2)
|
|
482
|
+
table.add_column("Problems", style="yellow", ratio=3)
|
|
483
|
+
table.add_column("Dependencies", style="magenta", ratio=2)
|
|
443
484
|
|
|
444
485
|
# Status emojis mapping
|
|
445
486
|
status_emoji = {
|
|
@@ -449,6 +490,14 @@ class WorkflowManager:
|
|
|
449
490
|
self.WorkflowStatus.MISSING: "[red]?[/red]",
|
|
450
491
|
}
|
|
451
492
|
|
|
493
|
+
# Status text mapping (colored)
|
|
494
|
+
status_text = {
|
|
495
|
+
self.WorkflowStatus.GOOD: "[green](GOOD)[/green]",
|
|
496
|
+
self.WorkflowStatus.FLAWED: "[yellow](FLAWED)[/yellow]",
|
|
497
|
+
self.WorkflowStatus.UNUSABLE: "[red](UNUSABLE)[/red]",
|
|
498
|
+
self.WorkflowStatus.MISSING: "[red](MISSING)[/red]",
|
|
499
|
+
}
|
|
500
|
+
|
|
452
501
|
dependency_status_emoji = {
|
|
453
502
|
self.WorkflowDependencyStatus.PERFECT: "[green]OK[/green]",
|
|
454
503
|
self.WorkflowDependencyStatus.GOOD: "[green]GOOD[/green]",
|
|
@@ -459,19 +508,37 @@ class WorkflowManager:
|
|
|
459
508
|
}
|
|
460
509
|
|
|
461
510
|
# Add rows for each workflow info
|
|
462
|
-
for wf_info in
|
|
463
|
-
#
|
|
464
|
-
file_path = wf_info.workflow_path
|
|
465
|
-
file_path_text = Text(file_path, style="cyan")
|
|
466
|
-
file_path_text.overflow = "fold" # Force wrapping
|
|
467
|
-
|
|
468
|
-
# Workflow name column with emoji based on status
|
|
511
|
+
for wf_info in filtered_workflow_infos:
|
|
512
|
+
# Workflow name column with emoji, name, colored status, and file path underneath
|
|
469
513
|
emoji = status_emoji.get(wf_info.status, "ERR: Unknown/Unexpected Workflow Status")
|
|
514
|
+
colored_status = status_text.get(wf_info.status, "(UNKNOWN)")
|
|
470
515
|
name = wf_info.workflow_name if wf_info.workflow_name else "*UNKNOWN*"
|
|
471
|
-
|
|
516
|
+
file_path = wf_info.workflow_path
|
|
517
|
+
workflow_name_with_path = Text.from_markup(
|
|
518
|
+
f"{emoji} - {name} {colored_status}\n[cyan dim]{file_path}[/cyan dim]"
|
|
519
|
+
)
|
|
520
|
+
workflow_name_with_path.overflow = "fold"
|
|
472
521
|
|
|
473
|
-
# Problems column -
|
|
474
|
-
|
|
522
|
+
# Problems column - collate by type
|
|
523
|
+
if not wf_info.problems:
|
|
524
|
+
problems = "No problems detected."
|
|
525
|
+
else:
|
|
526
|
+
# Group problems by type
|
|
527
|
+
problems_by_type = defaultdict(list)
|
|
528
|
+
for problem in wf_info.problems:
|
|
529
|
+
problems_by_type[type(problem)].append(problem)
|
|
530
|
+
|
|
531
|
+
# Collate each group
|
|
532
|
+
collated_strings = []
|
|
533
|
+
for problem_class, instances in problems_by_type.items():
|
|
534
|
+
collated_display = problem_class.collate_problems_for_display(instances)
|
|
535
|
+
collated_strings.append(collated_display)
|
|
536
|
+
|
|
537
|
+
# Format for display
|
|
538
|
+
if len(collated_strings) == 1:
|
|
539
|
+
problems = collated_strings[0]
|
|
540
|
+
else:
|
|
541
|
+
problems = "\n".join([f"{j + 1}. {problem}" for j, problem in enumerate(collated_strings)])
|
|
475
542
|
|
|
476
543
|
# Dependencies column
|
|
477
544
|
if wf_info.status == self.WorkflowStatus.MISSING or (
|
|
@@ -489,9 +556,7 @@ class WorkflowManager:
|
|
|
489
556
|
)
|
|
490
557
|
|
|
491
558
|
table.add_row(
|
|
492
|
-
|
|
493
|
-
wf_info.status.value,
|
|
494
|
-
file_path_text,
|
|
559
|
+
workflow_name_with_path,
|
|
495
560
|
problems,
|
|
496
561
|
dependencies,
|
|
497
562
|
)
|
|
@@ -870,9 +935,7 @@ class WorkflowManager:
|
|
|
870
935
|
workflow_path=str_path,
|
|
871
936
|
workflow_name=None,
|
|
872
937
|
workflow_dependencies=[],
|
|
873
|
-
problems=[
|
|
874
|
-
"Workflow could not be found at the file path specified. It will be removed from the configuration."
|
|
875
|
-
],
|
|
938
|
+
problems=[WorkflowNotFoundProblem()],
|
|
876
939
|
)
|
|
877
940
|
details = f"Attempted to load workflow metadata for a file at '{complete_file_path}. Failed because no file could be found at that path."
|
|
878
941
|
return LoadWorkflowMetadataResultFailure(result_details=details)
|
|
@@ -886,9 +949,7 @@ class WorkflowManager:
|
|
|
886
949
|
workflow_path=str_path,
|
|
887
950
|
workflow_name=None,
|
|
888
951
|
workflow_dependencies=[],
|
|
889
|
-
problems=[
|
|
890
|
-
f"Failed as it had {len(matches)} sections titled '{block_name}', and we expect exactly 1 such section."
|
|
891
|
-
],
|
|
952
|
+
problems=[InvalidMetadataSectionCountProblem(section_name=block_name, count=len(matches))],
|
|
892
953
|
)
|
|
893
954
|
details = f"Attempted to load workflow metadata for a file at '{complete_file_path}'. Failed as it had {len(matches)} sections titled '{block_name}', and we expect exactly 1 such section."
|
|
894
955
|
return LoadWorkflowMetadataResultFailure(result_details=details)
|
|
@@ -907,7 +968,7 @@ class WorkflowManager:
|
|
|
907
968
|
workflow_path=str_path,
|
|
908
969
|
workflow_name=None,
|
|
909
970
|
workflow_dependencies=[],
|
|
910
|
-
problems=[
|
|
971
|
+
problems=[InvalidTomlFormatProblem(error_message=str(err))],
|
|
911
972
|
)
|
|
912
973
|
details = f"Attempted to load workflow metadata for a file at '{complete_file_path}'. Failed because the metadata was not valid TOML: {err}"
|
|
913
974
|
return LoadWorkflowMetadataResultFailure(result_details=details)
|
|
@@ -922,7 +983,7 @@ class WorkflowManager:
|
|
|
922
983
|
workflow_path=str_path,
|
|
923
984
|
workflow_name=None,
|
|
924
985
|
workflow_dependencies=[],
|
|
925
|
-
problems=[f"
|
|
986
|
+
problems=[MissingTomlSectionProblem(section_path=f"[{tool_header}.{griptape_nodes_header}]")],
|
|
926
987
|
)
|
|
927
988
|
details = f"Attempted to load workflow metadata for a file at '{complete_file_path}'. Failed because the '[{tool_header}.{griptape_nodes_header}]' section could not be found: {err}"
|
|
928
989
|
return LoadWorkflowMetadataResultFailure(result_details=details)
|
|
@@ -938,7 +999,9 @@ class WorkflowManager:
|
|
|
938
999
|
workflow_name=None,
|
|
939
1000
|
workflow_dependencies=[],
|
|
940
1001
|
problems=[
|
|
941
|
-
|
|
1002
|
+
InvalidMetadataSchemaProblem(
|
|
1003
|
+
section_path=f"[{tool_header}.{griptape_nodes_header}]", error_message=str(err)
|
|
1004
|
+
)
|
|
942
1005
|
],
|
|
943
1006
|
)
|
|
944
1007
|
details = f"Attempted to load workflow metadata for a file at '{complete_file_path}'. Failed because the metadata in the '[{tool_header}.{griptape_nodes_header}]' section did not match the requisite schema with error: {err}"
|
|
@@ -953,15 +1016,23 @@ class WorkflowManager:
|
|
|
953
1016
|
if workflow_metadata.creation_date is None:
|
|
954
1017
|
# Assign it to the epoch start and flag it as a warning.
|
|
955
1018
|
workflow_metadata.creation_date = WorkflowManager.EPOCH_START
|
|
956
|
-
problems.append(
|
|
957
|
-
f"Workflow metadata was missing a creation date. Defaulting to {WorkflowManager.EPOCH_START}. This value will be replaced with the current date the first time it is saved."
|
|
958
|
-
)
|
|
1019
|
+
problems.append(MissingCreationDateProblem(default_date=str(WorkflowManager.EPOCH_START)))
|
|
959
1020
|
if workflow_metadata.last_modified_date is None:
|
|
960
1021
|
# Assign it to the epoch start and flag it as a warning.
|
|
961
1022
|
workflow_metadata.last_modified_date = WorkflowManager.EPOCH_START
|
|
962
|
-
problems.append(
|
|
963
|
-
|
|
964
|
-
|
|
1023
|
+
problems.append(MissingLastModifiedDateProblem(default_date=str(WorkflowManager.EPOCH_START)))
|
|
1024
|
+
|
|
1025
|
+
# Get list of registered libraries once (silent check - no error logging)
|
|
1026
|
+
list_libraries_request = ListRegisteredLibrariesRequest()
|
|
1027
|
+
list_libraries_result = GriptapeNodes.LibraryManager().on_list_registered_libraries_request(
|
|
1028
|
+
list_libraries_request
|
|
1029
|
+
)
|
|
1030
|
+
|
|
1031
|
+
if not isinstance(list_libraries_result, ListRegisteredLibrariesResultSuccess):
|
|
1032
|
+
# Should not happen, but handle gracefully - treat as no libraries registered
|
|
1033
|
+
registered_libraries = []
|
|
1034
|
+
else:
|
|
1035
|
+
registered_libraries = list_libraries_result.libraries
|
|
965
1036
|
|
|
966
1037
|
dependency_infos = []
|
|
967
1038
|
for node_library_referenced in workflow_metadata.node_libraries_referenced:
|
|
@@ -972,7 +1043,7 @@ class WorkflowManager:
|
|
|
972
1043
|
except Exception:
|
|
973
1044
|
had_critical_error = True
|
|
974
1045
|
problems.append(
|
|
975
|
-
|
|
1046
|
+
InvalidDependencyVersionStringProblem(library_name=library_name, version_string=desired_version_str)
|
|
976
1047
|
)
|
|
977
1048
|
dependency_infos.append(
|
|
978
1049
|
WorkflowManager.WorkflowDependencyInfo(
|
|
@@ -985,20 +1056,32 @@ class WorkflowManager:
|
|
|
985
1056
|
# SKIP IT.
|
|
986
1057
|
continue
|
|
987
1058
|
# See how our desired version compares against the actual library we (may) have.
|
|
988
|
-
#
|
|
1059
|
+
# Check if library is registered (silent check - no error logging)
|
|
1060
|
+
if library_name not in registered_libraries:
|
|
1061
|
+
# Library not registered
|
|
1062
|
+
had_critical_error = True
|
|
1063
|
+
problems.append(LibraryNotRegisteredProblem(library_name=library_name))
|
|
1064
|
+
dependency_infos.append(
|
|
1065
|
+
WorkflowManager.WorkflowDependencyInfo(
|
|
1066
|
+
library_name=library_name,
|
|
1067
|
+
version_requested=desired_version_str,
|
|
1068
|
+
version_present=None,
|
|
1069
|
+
status=WorkflowManager.WorkflowDependencyStatus.MISSING,
|
|
1070
|
+
)
|
|
1071
|
+
)
|
|
1072
|
+
# SKIP IT.
|
|
1073
|
+
continue
|
|
1074
|
+
|
|
1075
|
+
# Get library metadata (we know library is registered, so no error logging)
|
|
989
1076
|
library_metadata_request = GetLibraryMetadataRequest(library=library_name)
|
|
990
|
-
# NOTE: Per https://github.com/griptape-ai/griptape-vsl-gui/issues/1123, we
|
|
991
|
-
# generate a FLOOD of error messages here that can swamp the GUI. We'll call
|
|
992
|
-
# directly instead of the usual handle_request() path so we don't generate those.
|
|
993
1077
|
library_metadata_result = GriptapeNodes.LibraryManager().get_library_metadata_request(
|
|
994
1078
|
library_metadata_request
|
|
995
1079
|
)
|
|
1080
|
+
|
|
996
1081
|
if not isinstance(library_metadata_result, GetLibraryMetadataResultSuccess):
|
|
997
|
-
#
|
|
1082
|
+
# Should not happen since we verified library is registered, but handle gracefully
|
|
998
1083
|
had_critical_error = True
|
|
999
|
-
problems.append(
|
|
1000
|
-
f"Library '{library_name}' was not successfully registered. It may have other problems that prevented it from loading."
|
|
1001
|
-
)
|
|
1084
|
+
problems.append(LibraryNotRegisteredProblem(library_name=library_name))
|
|
1002
1085
|
dependency_infos.append(
|
|
1003
1086
|
WorkflowManager.WorkflowDependencyInfo(
|
|
1004
1087
|
library_name=library_name,
|
|
@@ -1018,7 +1101,7 @@ class WorkflowManager:
|
|
|
1018
1101
|
except Exception:
|
|
1019
1102
|
had_critical_error = True
|
|
1020
1103
|
problems.append(
|
|
1021
|
-
|
|
1104
|
+
InvalidLibraryVersionStringProblem(library_name=library_name, version_string=library_version_str)
|
|
1022
1105
|
)
|
|
1023
1106
|
dependency_infos.append(
|
|
1024
1107
|
WorkflowManager.WorkflowDependencyInfo(
|
|
@@ -1043,24 +1126,40 @@ class WorkflowManager:
|
|
|
1043
1126
|
delta = library_version.minor - desired_version.minor
|
|
1044
1127
|
if delta < 0:
|
|
1045
1128
|
problems.append(
|
|
1046
|
-
|
|
1129
|
+
LibraryVersionBelowRequiredProblem(
|
|
1130
|
+
library_name=library_name,
|
|
1131
|
+
current_version=str(library_version),
|
|
1132
|
+
required_version=str(desired_version),
|
|
1133
|
+
)
|
|
1047
1134
|
)
|
|
1048
1135
|
status = WorkflowManager.WorkflowDependencyStatus.BAD
|
|
1049
1136
|
had_critical_error = True
|
|
1050
1137
|
elif delta > WorkflowManager.MAX_MINOR_VERSION_DEVIATION:
|
|
1051
1138
|
problems.append(
|
|
1052
|
-
|
|
1139
|
+
LibraryVersionLargeDifferenceProblem(
|
|
1140
|
+
library_name=library_name,
|
|
1141
|
+
workflow_version=str(desired_version),
|
|
1142
|
+
current_version=str(library_version),
|
|
1143
|
+
)
|
|
1053
1144
|
)
|
|
1054
1145
|
status = WorkflowManager.WorkflowDependencyStatus.BAD
|
|
1055
1146
|
had_critical_error = True
|
|
1056
1147
|
else:
|
|
1057
1148
|
problems.append(
|
|
1058
|
-
|
|
1149
|
+
LibraryVersionMinorDifferenceProblem(
|
|
1150
|
+
library_name=library_name,
|
|
1151
|
+
workflow_version=str(desired_version),
|
|
1152
|
+
current_version=str(library_version),
|
|
1153
|
+
)
|
|
1059
1154
|
)
|
|
1060
1155
|
status = WorkflowManager.WorkflowDependencyStatus.CAUTION
|
|
1061
1156
|
else:
|
|
1062
1157
|
problems.append(
|
|
1063
|
-
|
|
1158
|
+
LibraryVersionMajorMismatchProblem(
|
|
1159
|
+
library_name=library_name,
|
|
1160
|
+
workflow_version=str(desired_version),
|
|
1161
|
+
current_version=str(library_version),
|
|
1162
|
+
)
|
|
1064
1163
|
)
|
|
1065
1164
|
status = WorkflowManager.WorkflowDependencyStatus.BAD
|
|
1066
1165
|
had_critical_error = True
|
|
@@ -1080,7 +1179,7 @@ class WorkflowManager:
|
|
|
1080
1179
|
workflow_metadata
|
|
1081
1180
|
)
|
|
1082
1181
|
for issue in workflow_version_issues:
|
|
1083
|
-
problems.append(issue.
|
|
1182
|
+
problems.append(issue.problem)
|
|
1084
1183
|
if issue.severity == WorkflowManager.WorkflowStatus.UNUSABLE:
|
|
1085
1184
|
had_critical_error = True
|
|
1086
1185
|
|
|
@@ -2383,82 +2482,11 @@ class WorkflowManager:
|
|
|
2383
2482
|
workflow_name: str,
|
|
2384
2483
|
import_recorder: ImportRecorder,
|
|
2385
2484
|
) -> list[ast.AST]:
|
|
2386
|
-
import_recorder.add_from_import(
|
|
2387
|
-
"griptape_nodes.retained_mode.events.library_events", "GetAllInfoForAllLibrariesRequest"
|
|
2388
|
-
)
|
|
2389
|
-
import_recorder.add_from_import(
|
|
2390
|
-
"griptape_nodes.retained_mode.events.library_events", "GetAllInfoForAllLibrariesResultSuccess"
|
|
2391
|
-
)
|
|
2392
|
-
import_recorder.add_from_import(
|
|
2393
|
-
"griptape_nodes.retained_mode.events.library_events", "ReloadAllLibrariesRequest"
|
|
2394
|
-
)
|
|
2485
|
+
import_recorder.add_from_import("griptape_nodes.retained_mode.events.library_events", "LoadLibrariesRequest")
|
|
2395
2486
|
|
|
2396
2487
|
code_blocks: list[ast.AST] = []
|
|
2397
2488
|
|
|
2398
|
-
|
|
2399
|
-
targets=[ast.Name(id="response", ctx=ast.Store())],
|
|
2400
|
-
value=ast.Call(
|
|
2401
|
-
func=ast.Attribute(
|
|
2402
|
-
value=ast.Name(id="GriptapeNodes", ctx=ast.Load()),
|
|
2403
|
-
attr="handle_request",
|
|
2404
|
-
ctx=ast.Load(),
|
|
2405
|
-
),
|
|
2406
|
-
args=[
|
|
2407
|
-
ast.Call(
|
|
2408
|
-
func=ast.Name(id="GetAllInfoForAllLibrariesRequest", ctx=ast.Load()),
|
|
2409
|
-
args=[],
|
|
2410
|
-
keywords=[],
|
|
2411
|
-
)
|
|
2412
|
-
],
|
|
2413
|
-
keywords=[],
|
|
2414
|
-
),
|
|
2415
|
-
)
|
|
2416
|
-
ast.fix_missing_locations(response_assign)
|
|
2417
|
-
code_blocks.append(response_assign)
|
|
2418
|
-
|
|
2419
|
-
isinstance_test = ast.Call(
|
|
2420
|
-
func=ast.Name(id="isinstance", ctx=ast.Load()),
|
|
2421
|
-
args=[
|
|
2422
|
-
ast.Name(id="response", ctx=ast.Load()),
|
|
2423
|
-
ast.Name(id="GetAllInfoForAllLibrariesResultSuccess", ctx=ast.Load()),
|
|
2424
|
-
],
|
|
2425
|
-
keywords=[],
|
|
2426
|
-
)
|
|
2427
|
-
ast.fix_missing_locations(isinstance_test)
|
|
2428
|
-
|
|
2429
|
-
len_call = ast.Call(
|
|
2430
|
-
func=ast.Name(id="len", ctx=ast.Load()),
|
|
2431
|
-
args=[
|
|
2432
|
-
ast.Call(
|
|
2433
|
-
func=ast.Attribute(
|
|
2434
|
-
value=ast.Attribute(
|
|
2435
|
-
value=ast.Name(id="response", ctx=ast.Load()),
|
|
2436
|
-
attr="library_name_to_library_info",
|
|
2437
|
-
ctx=ast.Load(),
|
|
2438
|
-
),
|
|
2439
|
-
attr="keys",
|
|
2440
|
-
ctx=ast.Load(),
|
|
2441
|
-
),
|
|
2442
|
-
args=[],
|
|
2443
|
-
keywords=[],
|
|
2444
|
-
)
|
|
2445
|
-
],
|
|
2446
|
-
keywords=[],
|
|
2447
|
-
)
|
|
2448
|
-
compare_len = ast.Compare(
|
|
2449
|
-
left=len_call,
|
|
2450
|
-
ops=[ast.Lt()],
|
|
2451
|
-
comparators=[ast.Constant(value=1)],
|
|
2452
|
-
)
|
|
2453
|
-
ast.fix_missing_locations(compare_len)
|
|
2454
|
-
|
|
2455
|
-
test = ast.BoolOp(
|
|
2456
|
-
op=ast.And(),
|
|
2457
|
-
values=[isinstance_test, compare_len],
|
|
2458
|
-
)
|
|
2459
|
-
ast.fix_missing_locations(test)
|
|
2460
|
-
|
|
2461
|
-
# 3) the body: GriptapeNodes.handle_request(ReloadAllLibrariesRequest())
|
|
2489
|
+
# Generate load libraries request call
|
|
2462
2490
|
# TODO (https://github.com/griptape-ai/griptape-nodes/issues/1615): Generate requests to load ONLY the libraries used in this workflow
|
|
2463
2491
|
load_call = ast.Expr(
|
|
2464
2492
|
value=ast.Call(
|
|
@@ -2469,7 +2497,7 @@ class WorkflowManager:
|
|
|
2469
2497
|
),
|
|
2470
2498
|
args=[
|
|
2471
2499
|
ast.Call(
|
|
2472
|
-
func=ast.Name(id="
|
|
2500
|
+
func=ast.Name(id="LoadLibrariesRequest", ctx=ast.Load()),
|
|
2473
2501
|
args=[],
|
|
2474
2502
|
keywords=[],
|
|
2475
2503
|
)
|
|
@@ -2478,17 +2506,9 @@ class WorkflowManager:
|
|
|
2478
2506
|
)
|
|
2479
2507
|
)
|
|
2480
2508
|
ast.fix_missing_locations(load_call)
|
|
2509
|
+
code_blocks.append(load_call)
|
|
2481
2510
|
|
|
2482
|
-
#
|
|
2483
|
-
if_node = ast.If(
|
|
2484
|
-
test=test,
|
|
2485
|
-
body=[load_call],
|
|
2486
|
-
orelse=[],
|
|
2487
|
-
)
|
|
2488
|
-
ast.fix_missing_locations(if_node)
|
|
2489
|
-
code_blocks.append(if_node)
|
|
2490
|
-
|
|
2491
|
-
# 5) context_manager = GriptapeNodes.ContextManager()
|
|
2511
|
+
# Generate context manager assignment
|
|
2492
2512
|
assign_context_manager = ast.Assign(
|
|
2493
2513
|
targets=[ast.Name(id="context_manager", ctx=ast.Store())],
|
|
2494
2514
|
value=ast.Call(
|
|
@@ -4097,40 +4117,98 @@ class WorkflowManager:
|
|
|
4097
4117
|
Returns:
|
|
4098
4118
|
WorkflowRegistrationResult with succeeded and failed workflow names
|
|
4099
4119
|
"""
|
|
4120
|
+
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
4121
|
+
|
|
4100
4122
|
succeeded = []
|
|
4101
4123
|
failed = []
|
|
4102
4124
|
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
# Check if the file has workflow metadata before processing
|
|
4106
|
-
metadata_blocks = self.get_workflow_metadata(
|
|
4107
|
-
workflow_file, block_name=WorkflowManager.WORKFLOW_METADATA_HEADER
|
|
4108
|
-
)
|
|
4109
|
-
if len(metadata_blocks) == 1:
|
|
4110
|
-
workflow_name = self._process_single_workflow_file(workflow_file)
|
|
4111
|
-
if workflow_name:
|
|
4112
|
-
succeeded.append(workflow_name)
|
|
4113
|
-
else:
|
|
4114
|
-
failed.append(str(workflow_file))
|
|
4125
|
+
# First pass: collect all workflow files to determine total count
|
|
4126
|
+
all_workflow_files: list[Path] = []
|
|
4115
4127
|
|
|
4116
|
-
def
|
|
4117
|
-
"""
|
|
4128
|
+
def collect_workflow_files(path: Path) -> None:
|
|
4129
|
+
"""Collect workflow files from a path."""
|
|
4118
4130
|
if not path.exists():
|
|
4119
|
-
failed.append(str(path))
|
|
4120
4131
|
return
|
|
4121
4132
|
if path.is_dir():
|
|
4122
|
-
# Process all Python files recursively in the directory
|
|
4123
|
-
# Exclude .venv directories to avoid encoding issues with test files
|
|
4124
4133
|
for workflow_file in path.rglob("*.py"):
|
|
4125
|
-
# Skip files in .venv directories
|
|
4126
4134
|
if ".venv" in workflow_file.parts:
|
|
4127
4135
|
continue
|
|
4128
|
-
|
|
4136
|
+
# Check if file has workflow metadata
|
|
4137
|
+
try:
|
|
4138
|
+
metadata_blocks = self.get_workflow_metadata(
|
|
4139
|
+
workflow_file, block_name=WorkflowManager.WORKFLOW_METADATA_HEADER
|
|
4140
|
+
)
|
|
4141
|
+
if len(metadata_blocks) == 1:
|
|
4142
|
+
all_workflow_files.append(workflow_file)
|
|
4143
|
+
except Exception as e:
|
|
4144
|
+
# Skip files that can't be read or parsed
|
|
4145
|
+
logger.debug("Skipping workflow file %s due to error: %s", workflow_file, e)
|
|
4146
|
+
continue
|
|
4129
4147
|
elif path.suffix == ".py":
|
|
4130
|
-
|
|
4148
|
+
try:
|
|
4149
|
+
metadata_blocks = self.get_workflow_metadata(
|
|
4150
|
+
path, block_name=WorkflowManager.WORKFLOW_METADATA_HEADER
|
|
4151
|
+
)
|
|
4152
|
+
if len(metadata_blocks) == 1:
|
|
4153
|
+
all_workflow_files.append(path)
|
|
4154
|
+
except Exception as e:
|
|
4155
|
+
logger.debug("Skipping workflow file %s due to error: %s", path, e)
|
|
4131
4156
|
|
|
4157
|
+
# Collect all workflow files first
|
|
4132
4158
|
for workflow_to_register in workflows_to_register:
|
|
4133
|
-
|
|
4159
|
+
collect_workflow_files(Path(workflow_to_register))
|
|
4160
|
+
|
|
4161
|
+
# Track progress
|
|
4162
|
+
total_workflows = len(all_workflow_files)
|
|
4163
|
+
|
|
4164
|
+
# Second pass: process each workflow file with progress events
|
|
4165
|
+
for current_index, workflow_file in enumerate(all_workflow_files, start=1):
|
|
4166
|
+
workflow_name = str(workflow_file.name)
|
|
4167
|
+
|
|
4168
|
+
# Emit loading event
|
|
4169
|
+
GriptapeNodes.EventManager().put_event(
|
|
4170
|
+
AppEvent(
|
|
4171
|
+
payload=EngineInitializationProgress(
|
|
4172
|
+
phase=InitializationPhase.WORKFLOWS,
|
|
4173
|
+
item_name=workflow_name,
|
|
4174
|
+
status=InitializationStatus.LOADING,
|
|
4175
|
+
current=current_index,
|
|
4176
|
+
total=total_workflows,
|
|
4177
|
+
)
|
|
4178
|
+
)
|
|
4179
|
+
)
|
|
4180
|
+
|
|
4181
|
+
# Process the workflow
|
|
4182
|
+
result_name = self._process_single_workflow_file(workflow_file)
|
|
4183
|
+
if result_name:
|
|
4184
|
+
succeeded.append(result_name)
|
|
4185
|
+
# Emit success event
|
|
4186
|
+
GriptapeNodes.EventManager().put_event(
|
|
4187
|
+
AppEvent(
|
|
4188
|
+
payload=EngineInitializationProgress(
|
|
4189
|
+
phase=InitializationPhase.WORKFLOWS,
|
|
4190
|
+
item_name=workflow_name,
|
|
4191
|
+
status=InitializationStatus.COMPLETE,
|
|
4192
|
+
current=current_index,
|
|
4193
|
+
total=total_workflows,
|
|
4194
|
+
)
|
|
4195
|
+
)
|
|
4196
|
+
)
|
|
4197
|
+
else:
|
|
4198
|
+
failed.append(str(workflow_file))
|
|
4199
|
+
# Emit failure event
|
|
4200
|
+
GriptapeNodes.EventManager().put_event(
|
|
4201
|
+
AppEvent(
|
|
4202
|
+
payload=EngineInitializationProgress(
|
|
4203
|
+
phase=InitializationPhase.WORKFLOWS,
|
|
4204
|
+
item_name=workflow_name,
|
|
4205
|
+
status=InitializationStatus.FAILED,
|
|
4206
|
+
current=current_index,
|
|
4207
|
+
total=total_workflows,
|
|
4208
|
+
error="Failed to process workflow file",
|
|
4209
|
+
)
|
|
4210
|
+
)
|
|
4211
|
+
)
|
|
4134
4212
|
|
|
4135
4213
|
return WorkflowRegistrationResult(succeeded=succeeded, failed=failed)
|
|
4136
4214
|
|