griptape-nodes 0.62.3__py3-none-any.whl → 0.63.1__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/cli/commands/models.py +21 -4
- 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/library_events.py +32 -3
- griptape_nodes/retained_mode/events/model_events.py +4 -4
- 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 +159 -75
- griptape_nodes/retained_mode/managers/model_manager.py +182 -205
- 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 +154 -137
- 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.3.dist-info → griptape_nodes-0.63.1.dist-info}/METADATA +3 -2
- {griptape_nodes-0.62.3.dist-info → griptape_nodes-0.63.1.dist-info}/RECORD +76 -23
- {griptape_nodes-0.62.3.dist-info → griptape_nodes-0.63.1.dist-info}/WHEEL +0 -0
- {griptape_nodes-0.62.3.dist-info → griptape_nodes-0.63.1.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
|
|
@@ -54,6 +55,8 @@ from griptape_nodes.retained_mode.events.flow_events import (
|
|
|
54
55
|
from griptape_nodes.retained_mode.events.library_events import (
|
|
55
56
|
GetLibraryMetadataRequest,
|
|
56
57
|
GetLibraryMetadataResultSuccess,
|
|
58
|
+
ListRegisteredLibrariesRequest,
|
|
59
|
+
ListRegisteredLibrariesResultSuccess,
|
|
57
60
|
)
|
|
58
61
|
from griptape_nodes.retained_mode.events.object_events import ClearAllObjectStateRequest
|
|
59
62
|
from griptape_nodes.retained_mode.events.workflow_events import (
|
|
@@ -118,6 +121,22 @@ from griptape_nodes.retained_mode.events.workflow_events import (
|
|
|
118
121
|
from griptape_nodes.retained_mode.griptape_nodes import (
|
|
119
122
|
GriptapeNodes,
|
|
120
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
|
+
)
|
|
121
140
|
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
122
141
|
|
|
123
142
|
if TYPE_CHECKING:
|
|
@@ -128,6 +147,7 @@ if TYPE_CHECKING:
|
|
|
128
147
|
from griptape_nodes.retained_mode.events.base_events import ResultPayload
|
|
129
148
|
from griptape_nodes.retained_mode.events.node_events import SerializedNodeCommands, SetLockNodeStateRequest
|
|
130
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
|
|
131
151
|
|
|
132
152
|
|
|
133
153
|
T = TypeVar("T")
|
|
@@ -189,7 +209,7 @@ class WorkflowManager:
|
|
|
189
209
|
workflow_path: str
|
|
190
210
|
workflow_name: str | None = None
|
|
191
211
|
workflow_dependencies: list[WorkflowManager.WorkflowDependencyInfo] = field(default_factory=list)
|
|
192
|
-
problems: list[
|
|
212
|
+
problems: list[WorkflowProblem] = field(default_factory=list)
|
|
193
213
|
|
|
194
214
|
_workflow_file_path_to_info: dict[str, WorkflowInfo]
|
|
195
215
|
|
|
@@ -419,30 +439,48 @@ class WorkflowManager:
|
|
|
419
439
|
|
|
420
440
|
return matches
|
|
421
441
|
|
|
422
|
-
def print_workflow_load_status(self) -> None:
|
|
442
|
+
def print_workflow_load_status(self, min_status: WorkflowStatus = WorkflowStatus.FLAWED) -> None: # noqa: PLR0915
|
|
423
443
|
workflow_file_paths = self.get_workflows_attempted_to_load()
|
|
424
444
|
workflow_infos = []
|
|
425
445
|
for workflow_file_path in workflow_file_paths:
|
|
426
446
|
workflow_info = self.get_workflow_info_for_attempted_load(workflow_file_path)
|
|
427
447
|
workflow_infos.append(workflow_info)
|
|
428
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
|
+
|
|
429
459
|
console = Console()
|
|
430
460
|
|
|
431
461
|
# Check if the list is empty
|
|
432
|
-
if not
|
|
433
|
-
# Display a message indicating no workflows are available
|
|
462
|
+
if not filtered_workflow_infos:
|
|
434
463
|
empty_message = Text("No workflow information available", style="italic")
|
|
435
464
|
panel = Panel(empty_message, title="Workflow Information", border_style="blue")
|
|
436
465
|
console.print(panel)
|
|
437
466
|
return
|
|
438
467
|
|
|
439
|
-
#
|
|
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
|
|
440
480
|
table = Table(show_header=True, box=HEAVY_EDGE, show_lines=True, expand=True)
|
|
441
|
-
table.add_column("Workflow
|
|
442
|
-
table.add_column("
|
|
443
|
-
table.add_column("
|
|
444
|
-
table.add_column("Problems", style="yellow")
|
|
445
|
-
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)
|
|
446
484
|
|
|
447
485
|
# Status emojis mapping
|
|
448
486
|
status_emoji = {
|
|
@@ -452,6 +490,14 @@ class WorkflowManager:
|
|
|
452
490
|
self.WorkflowStatus.MISSING: "[red]?[/red]",
|
|
453
491
|
}
|
|
454
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
|
+
|
|
455
501
|
dependency_status_emoji = {
|
|
456
502
|
self.WorkflowDependencyStatus.PERFECT: "[green]OK[/green]",
|
|
457
503
|
self.WorkflowDependencyStatus.GOOD: "[green]GOOD[/green]",
|
|
@@ -462,19 +508,37 @@ class WorkflowManager:
|
|
|
462
508
|
}
|
|
463
509
|
|
|
464
510
|
# Add rows for each workflow info
|
|
465
|
-
for wf_info in
|
|
466
|
-
#
|
|
467
|
-
file_path = wf_info.workflow_path
|
|
468
|
-
file_path_text = Text(file_path, style="cyan")
|
|
469
|
-
file_path_text.overflow = "fold" # Force wrapping
|
|
470
|
-
|
|
471
|
-
# 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
|
|
472
513
|
emoji = status_emoji.get(wf_info.status, "ERR: Unknown/Unexpected Workflow Status")
|
|
514
|
+
colored_status = status_text.get(wf_info.status, "(UNKNOWN)")
|
|
473
515
|
name = wf_info.workflow_name if wf_info.workflow_name else "*UNKNOWN*"
|
|
474
|
-
|
|
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"
|
|
475
521
|
|
|
476
|
-
# Problems column -
|
|
477
|
-
|
|
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)])
|
|
478
542
|
|
|
479
543
|
# Dependencies column
|
|
480
544
|
if wf_info.status == self.WorkflowStatus.MISSING or (
|
|
@@ -492,9 +556,7 @@ class WorkflowManager:
|
|
|
492
556
|
)
|
|
493
557
|
|
|
494
558
|
table.add_row(
|
|
495
|
-
|
|
496
|
-
wf_info.status.value,
|
|
497
|
-
file_path_text,
|
|
559
|
+
workflow_name_with_path,
|
|
498
560
|
problems,
|
|
499
561
|
dependencies,
|
|
500
562
|
)
|
|
@@ -873,9 +935,7 @@ class WorkflowManager:
|
|
|
873
935
|
workflow_path=str_path,
|
|
874
936
|
workflow_name=None,
|
|
875
937
|
workflow_dependencies=[],
|
|
876
|
-
problems=[
|
|
877
|
-
"Workflow could not be found at the file path specified. It will be removed from the configuration."
|
|
878
|
-
],
|
|
938
|
+
problems=[WorkflowNotFoundProblem()],
|
|
879
939
|
)
|
|
880
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."
|
|
881
941
|
return LoadWorkflowMetadataResultFailure(result_details=details)
|
|
@@ -889,9 +949,7 @@ class WorkflowManager:
|
|
|
889
949
|
workflow_path=str_path,
|
|
890
950
|
workflow_name=None,
|
|
891
951
|
workflow_dependencies=[],
|
|
892
|
-
problems=[
|
|
893
|
-
f"Failed as it had {len(matches)} sections titled '{block_name}', and we expect exactly 1 such section."
|
|
894
|
-
],
|
|
952
|
+
problems=[InvalidMetadataSectionCountProblem(section_name=block_name, count=len(matches))],
|
|
895
953
|
)
|
|
896
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."
|
|
897
955
|
return LoadWorkflowMetadataResultFailure(result_details=details)
|
|
@@ -910,7 +968,7 @@ class WorkflowManager:
|
|
|
910
968
|
workflow_path=str_path,
|
|
911
969
|
workflow_name=None,
|
|
912
970
|
workflow_dependencies=[],
|
|
913
|
-
problems=[
|
|
971
|
+
problems=[InvalidTomlFormatProblem(error_message=str(err))],
|
|
914
972
|
)
|
|
915
973
|
details = f"Attempted to load workflow metadata for a file at '{complete_file_path}'. Failed because the metadata was not valid TOML: {err}"
|
|
916
974
|
return LoadWorkflowMetadataResultFailure(result_details=details)
|
|
@@ -925,7 +983,7 @@ class WorkflowManager:
|
|
|
925
983
|
workflow_path=str_path,
|
|
926
984
|
workflow_name=None,
|
|
927
985
|
workflow_dependencies=[],
|
|
928
|
-
problems=[f"
|
|
986
|
+
problems=[MissingTomlSectionProblem(section_path=f"[{tool_header}.{griptape_nodes_header}]")],
|
|
929
987
|
)
|
|
930
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}"
|
|
931
989
|
return LoadWorkflowMetadataResultFailure(result_details=details)
|
|
@@ -941,7 +999,9 @@ class WorkflowManager:
|
|
|
941
999
|
workflow_name=None,
|
|
942
1000
|
workflow_dependencies=[],
|
|
943
1001
|
problems=[
|
|
944
|
-
|
|
1002
|
+
InvalidMetadataSchemaProblem(
|
|
1003
|
+
section_path=f"[{tool_header}.{griptape_nodes_header}]", error_message=str(err)
|
|
1004
|
+
)
|
|
945
1005
|
],
|
|
946
1006
|
)
|
|
947
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}"
|
|
@@ -956,15 +1016,23 @@ class WorkflowManager:
|
|
|
956
1016
|
if workflow_metadata.creation_date is None:
|
|
957
1017
|
# Assign it to the epoch start and flag it as a warning.
|
|
958
1018
|
workflow_metadata.creation_date = WorkflowManager.EPOCH_START
|
|
959
|
-
problems.append(
|
|
960
|
-
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."
|
|
961
|
-
)
|
|
1019
|
+
problems.append(MissingCreationDateProblem(default_date=str(WorkflowManager.EPOCH_START)))
|
|
962
1020
|
if workflow_metadata.last_modified_date is None:
|
|
963
1021
|
# Assign it to the epoch start and flag it as a warning.
|
|
964
1022
|
workflow_metadata.last_modified_date = WorkflowManager.EPOCH_START
|
|
965
|
-
problems.append(
|
|
966
|
-
|
|
967
|
-
|
|
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
|
|
968
1036
|
|
|
969
1037
|
dependency_infos = []
|
|
970
1038
|
for node_library_referenced in workflow_metadata.node_libraries_referenced:
|
|
@@ -975,7 +1043,7 @@ class WorkflowManager:
|
|
|
975
1043
|
except Exception:
|
|
976
1044
|
had_critical_error = True
|
|
977
1045
|
problems.append(
|
|
978
|
-
|
|
1046
|
+
InvalidDependencyVersionStringProblem(library_name=library_name, version_string=desired_version_str)
|
|
979
1047
|
)
|
|
980
1048
|
dependency_infos.append(
|
|
981
1049
|
WorkflowManager.WorkflowDependencyInfo(
|
|
@@ -988,20 +1056,32 @@ class WorkflowManager:
|
|
|
988
1056
|
# SKIP IT.
|
|
989
1057
|
continue
|
|
990
1058
|
# See how our desired version compares against the actual library we (may) have.
|
|
991
|
-
#
|
|
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)
|
|
992
1076
|
library_metadata_request = GetLibraryMetadataRequest(library=library_name)
|
|
993
|
-
# NOTE: Per https://github.com/griptape-ai/griptape-vsl-gui/issues/1123, we
|
|
994
|
-
# generate a FLOOD of error messages here that can swamp the GUI. We'll call
|
|
995
|
-
# directly instead of the usual handle_request() path so we don't generate those.
|
|
996
1077
|
library_metadata_result = GriptapeNodes.LibraryManager().get_library_metadata_request(
|
|
997
1078
|
library_metadata_request
|
|
998
1079
|
)
|
|
1080
|
+
|
|
999
1081
|
if not isinstance(library_metadata_result, GetLibraryMetadataResultSuccess):
|
|
1000
|
-
#
|
|
1082
|
+
# Should not happen since we verified library is registered, but handle gracefully
|
|
1001
1083
|
had_critical_error = True
|
|
1002
|
-
problems.append(
|
|
1003
|
-
f"Library '{library_name}' was not successfully registered. It may have other problems that prevented it from loading."
|
|
1004
|
-
)
|
|
1084
|
+
problems.append(LibraryNotRegisteredProblem(library_name=library_name))
|
|
1005
1085
|
dependency_infos.append(
|
|
1006
1086
|
WorkflowManager.WorkflowDependencyInfo(
|
|
1007
1087
|
library_name=library_name,
|
|
@@ -1021,7 +1101,7 @@ class WorkflowManager:
|
|
|
1021
1101
|
except Exception:
|
|
1022
1102
|
had_critical_error = True
|
|
1023
1103
|
problems.append(
|
|
1024
|
-
|
|
1104
|
+
InvalidLibraryVersionStringProblem(library_name=library_name, version_string=library_version_str)
|
|
1025
1105
|
)
|
|
1026
1106
|
dependency_infos.append(
|
|
1027
1107
|
WorkflowManager.WorkflowDependencyInfo(
|
|
@@ -1046,24 +1126,40 @@ class WorkflowManager:
|
|
|
1046
1126
|
delta = library_version.minor - desired_version.minor
|
|
1047
1127
|
if delta < 0:
|
|
1048
1128
|
problems.append(
|
|
1049
|
-
|
|
1129
|
+
LibraryVersionBelowRequiredProblem(
|
|
1130
|
+
library_name=library_name,
|
|
1131
|
+
current_version=str(library_version),
|
|
1132
|
+
required_version=str(desired_version),
|
|
1133
|
+
)
|
|
1050
1134
|
)
|
|
1051
1135
|
status = WorkflowManager.WorkflowDependencyStatus.BAD
|
|
1052
1136
|
had_critical_error = True
|
|
1053
1137
|
elif delta > WorkflowManager.MAX_MINOR_VERSION_DEVIATION:
|
|
1054
1138
|
problems.append(
|
|
1055
|
-
|
|
1139
|
+
LibraryVersionLargeDifferenceProblem(
|
|
1140
|
+
library_name=library_name,
|
|
1141
|
+
workflow_version=str(desired_version),
|
|
1142
|
+
current_version=str(library_version),
|
|
1143
|
+
)
|
|
1056
1144
|
)
|
|
1057
1145
|
status = WorkflowManager.WorkflowDependencyStatus.BAD
|
|
1058
1146
|
had_critical_error = True
|
|
1059
1147
|
else:
|
|
1060
1148
|
problems.append(
|
|
1061
|
-
|
|
1149
|
+
LibraryVersionMinorDifferenceProblem(
|
|
1150
|
+
library_name=library_name,
|
|
1151
|
+
workflow_version=str(desired_version),
|
|
1152
|
+
current_version=str(library_version),
|
|
1153
|
+
)
|
|
1062
1154
|
)
|
|
1063
1155
|
status = WorkflowManager.WorkflowDependencyStatus.CAUTION
|
|
1064
1156
|
else:
|
|
1065
1157
|
problems.append(
|
|
1066
|
-
|
|
1158
|
+
LibraryVersionMajorMismatchProblem(
|
|
1159
|
+
library_name=library_name,
|
|
1160
|
+
workflow_version=str(desired_version),
|
|
1161
|
+
current_version=str(library_version),
|
|
1162
|
+
)
|
|
1067
1163
|
)
|
|
1068
1164
|
status = WorkflowManager.WorkflowDependencyStatus.BAD
|
|
1069
1165
|
had_critical_error = True
|
|
@@ -1083,7 +1179,7 @@ class WorkflowManager:
|
|
|
1083
1179
|
workflow_metadata
|
|
1084
1180
|
)
|
|
1085
1181
|
for issue in workflow_version_issues:
|
|
1086
|
-
problems.append(issue.
|
|
1182
|
+
problems.append(issue.problem)
|
|
1087
1183
|
if issue.severity == WorkflowManager.WorkflowStatus.UNUSABLE:
|
|
1088
1184
|
had_critical_error = True
|
|
1089
1185
|
|
|
@@ -2386,82 +2482,11 @@ class WorkflowManager:
|
|
|
2386
2482
|
workflow_name: str,
|
|
2387
2483
|
import_recorder: ImportRecorder,
|
|
2388
2484
|
) -> list[ast.AST]:
|
|
2389
|
-
import_recorder.add_from_import(
|
|
2390
|
-
"griptape_nodes.retained_mode.events.library_events", "GetAllInfoForAllLibrariesRequest"
|
|
2391
|
-
)
|
|
2392
|
-
import_recorder.add_from_import(
|
|
2393
|
-
"griptape_nodes.retained_mode.events.library_events", "GetAllInfoForAllLibrariesResultSuccess"
|
|
2394
|
-
)
|
|
2395
|
-
import_recorder.add_from_import(
|
|
2396
|
-
"griptape_nodes.retained_mode.events.library_events", "ReloadAllLibrariesRequest"
|
|
2397
|
-
)
|
|
2485
|
+
import_recorder.add_from_import("griptape_nodes.retained_mode.events.library_events", "LoadLibrariesRequest")
|
|
2398
2486
|
|
|
2399
2487
|
code_blocks: list[ast.AST] = []
|
|
2400
2488
|
|
|
2401
|
-
|
|
2402
|
-
targets=[ast.Name(id="response", ctx=ast.Store())],
|
|
2403
|
-
value=ast.Call(
|
|
2404
|
-
func=ast.Attribute(
|
|
2405
|
-
value=ast.Name(id="GriptapeNodes", ctx=ast.Load()),
|
|
2406
|
-
attr="handle_request",
|
|
2407
|
-
ctx=ast.Load(),
|
|
2408
|
-
),
|
|
2409
|
-
args=[
|
|
2410
|
-
ast.Call(
|
|
2411
|
-
func=ast.Name(id="GetAllInfoForAllLibrariesRequest", ctx=ast.Load()),
|
|
2412
|
-
args=[],
|
|
2413
|
-
keywords=[],
|
|
2414
|
-
)
|
|
2415
|
-
],
|
|
2416
|
-
keywords=[],
|
|
2417
|
-
),
|
|
2418
|
-
)
|
|
2419
|
-
ast.fix_missing_locations(response_assign)
|
|
2420
|
-
code_blocks.append(response_assign)
|
|
2421
|
-
|
|
2422
|
-
isinstance_test = ast.Call(
|
|
2423
|
-
func=ast.Name(id="isinstance", ctx=ast.Load()),
|
|
2424
|
-
args=[
|
|
2425
|
-
ast.Name(id="response", ctx=ast.Load()),
|
|
2426
|
-
ast.Name(id="GetAllInfoForAllLibrariesResultSuccess", ctx=ast.Load()),
|
|
2427
|
-
],
|
|
2428
|
-
keywords=[],
|
|
2429
|
-
)
|
|
2430
|
-
ast.fix_missing_locations(isinstance_test)
|
|
2431
|
-
|
|
2432
|
-
len_call = ast.Call(
|
|
2433
|
-
func=ast.Name(id="len", ctx=ast.Load()),
|
|
2434
|
-
args=[
|
|
2435
|
-
ast.Call(
|
|
2436
|
-
func=ast.Attribute(
|
|
2437
|
-
value=ast.Attribute(
|
|
2438
|
-
value=ast.Name(id="response", ctx=ast.Load()),
|
|
2439
|
-
attr="library_name_to_library_info",
|
|
2440
|
-
ctx=ast.Load(),
|
|
2441
|
-
),
|
|
2442
|
-
attr="keys",
|
|
2443
|
-
ctx=ast.Load(),
|
|
2444
|
-
),
|
|
2445
|
-
args=[],
|
|
2446
|
-
keywords=[],
|
|
2447
|
-
)
|
|
2448
|
-
],
|
|
2449
|
-
keywords=[],
|
|
2450
|
-
)
|
|
2451
|
-
compare_len = ast.Compare(
|
|
2452
|
-
left=len_call,
|
|
2453
|
-
ops=[ast.Lt()],
|
|
2454
|
-
comparators=[ast.Constant(value=1)],
|
|
2455
|
-
)
|
|
2456
|
-
ast.fix_missing_locations(compare_len)
|
|
2457
|
-
|
|
2458
|
-
test = ast.BoolOp(
|
|
2459
|
-
op=ast.And(),
|
|
2460
|
-
values=[isinstance_test, compare_len],
|
|
2461
|
-
)
|
|
2462
|
-
ast.fix_missing_locations(test)
|
|
2463
|
-
|
|
2464
|
-
# 3) the body: GriptapeNodes.handle_request(ReloadAllLibrariesRequest())
|
|
2489
|
+
# Generate load libraries request call
|
|
2465
2490
|
# TODO (https://github.com/griptape-ai/griptape-nodes/issues/1615): Generate requests to load ONLY the libraries used in this workflow
|
|
2466
2491
|
load_call = ast.Expr(
|
|
2467
2492
|
value=ast.Call(
|
|
@@ -2472,7 +2497,7 @@ class WorkflowManager:
|
|
|
2472
2497
|
),
|
|
2473
2498
|
args=[
|
|
2474
2499
|
ast.Call(
|
|
2475
|
-
func=ast.Name(id="
|
|
2500
|
+
func=ast.Name(id="LoadLibrariesRequest", ctx=ast.Load()),
|
|
2476
2501
|
args=[],
|
|
2477
2502
|
keywords=[],
|
|
2478
2503
|
)
|
|
@@ -2481,17 +2506,9 @@ class WorkflowManager:
|
|
|
2481
2506
|
)
|
|
2482
2507
|
)
|
|
2483
2508
|
ast.fix_missing_locations(load_call)
|
|
2509
|
+
code_blocks.append(load_call)
|
|
2484
2510
|
|
|
2485
|
-
#
|
|
2486
|
-
if_node = ast.If(
|
|
2487
|
-
test=test,
|
|
2488
|
-
body=[load_call],
|
|
2489
|
-
orelse=[],
|
|
2490
|
-
)
|
|
2491
|
-
ast.fix_missing_locations(if_node)
|
|
2492
|
-
code_blocks.append(if_node)
|
|
2493
|
-
|
|
2494
|
-
# 5) context_manager = GriptapeNodes.ContextManager()
|
|
2511
|
+
# Generate context manager assignment
|
|
2495
2512
|
assign_context_manager = ast.Assign(
|
|
2496
2513
|
targets=[ast.Name(id="context_manager", ctx=ast.Store())],
|
|
2497
2514
|
value=ast.Call(
|
griptape_nodes/servers/static.py
CHANGED
|
@@ -29,11 +29,6 @@ logger = logging.getLogger("griptape_nodes_api")
|
|
|
29
29
|
logging.getLogger("uvicorn").addHandler(RichHandler(show_time=True, show_path=False, markup=True, rich_tracebacks=True))
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
"""Create and configure the FastAPI application."""
|
|
33
|
-
app = FastAPI()
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@app.post("/static-upload-urls")
|
|
37
32
|
async def _create_static_file_upload_url(request: Request) -> dict:
|
|
38
33
|
"""Create a URL for uploading a static file.
|
|
39
34
|
|
|
@@ -47,7 +42,6 @@ async def _create_static_file_upload_url(request: Request) -> dict:
|
|
|
47
42
|
return {"url": url}
|
|
48
43
|
|
|
49
44
|
|
|
50
|
-
@app.put("/static-uploads/{file_path:path}")
|
|
51
45
|
async def _create_static_file(request: Request, file_path: str) -> dict:
|
|
52
46
|
"""Upload a static file to the static server."""
|
|
53
47
|
if not STATIC_SERVER_ENABLED:
|
|
@@ -76,8 +70,6 @@ async def _create_static_file(request: Request, file_path: str) -> dict:
|
|
|
76
70
|
return {"url": static_url}
|
|
77
71
|
|
|
78
72
|
|
|
79
|
-
@app.get("/static-uploads/{file_path_prefix:path}")
|
|
80
|
-
@app.get("/static-uploads/")
|
|
81
73
|
async def _list_static_files(file_path_prefix: str = "") -> dict:
|
|
82
74
|
"""List static files in the static server under the specified path prefix."""
|
|
83
75
|
if not STATIC_SERVER_ENABLED:
|
|
@@ -107,7 +99,6 @@ async def _list_static_files(file_path_prefix: str = "") -> dict:
|
|
|
107
99
|
return {"files": file_names}
|
|
108
100
|
|
|
109
101
|
|
|
110
|
-
@app.delete("/static-files/{file_path:path}")
|
|
111
102
|
async def _delete_static_file(file_path: str) -> dict:
|
|
112
103
|
"""Delete a static file from the static server."""
|
|
113
104
|
if not STATIC_SERVER_ENABLED:
|
|
@@ -139,11 +130,21 @@ async def _delete_static_file(file_path: str) -> dict:
|
|
|
139
130
|
return {"message": f"File {file_path} deleted successfully"}
|
|
140
131
|
|
|
141
132
|
|
|
142
|
-
def
|
|
143
|
-
"""
|
|
144
|
-
|
|
145
|
-
|
|
133
|
+
def start_static_server() -> None:
|
|
134
|
+
"""Run uvicorn server synchronously using uvicorn.run."""
|
|
135
|
+
logger.debug("Starting static server...")
|
|
136
|
+
|
|
137
|
+
# Create FastAPI app
|
|
138
|
+
app = FastAPI()
|
|
139
|
+
|
|
140
|
+
# Register routes
|
|
141
|
+
app.add_api_route("/static-upload-urls", _create_static_file_upload_url, methods=["POST"])
|
|
142
|
+
app.add_api_route("/static-uploads/{file_path:path}", _create_static_file, methods=["PUT"])
|
|
143
|
+
app.add_api_route("/static-uploads/{file_path_prefix:path}", _list_static_files, methods=["GET"])
|
|
144
|
+
app.add_api_route("/static-uploads/", _list_static_files, methods=["GET"])
|
|
145
|
+
app.add_api_route("/static-files/{file_path:path}", _delete_static_file, methods=["DELETE"])
|
|
146
146
|
|
|
147
|
+
# Add CORS middleware
|
|
147
148
|
app.add_middleware(
|
|
148
149
|
CORSMiddleware,
|
|
149
150
|
allow_origins=[
|
|
@@ -156,6 +157,10 @@ def _setup_app() -> None:
|
|
|
156
157
|
allow_headers=["*"],
|
|
157
158
|
)
|
|
158
159
|
|
|
160
|
+
# Mount static files
|
|
161
|
+
workspace_directory = Path(GriptapeNodes.ConfigManager().get_config_value("workspace_directory"))
|
|
162
|
+
static_files_directory = Path(GriptapeNodes.ConfigManager().get_config_value("static_files_directory"))
|
|
163
|
+
|
|
159
164
|
app.mount(
|
|
160
165
|
STATIC_SERVER_URL,
|
|
161
166
|
StaticFiles(directory=workspace_directory),
|
|
@@ -170,12 +175,6 @@ def _setup_app() -> None:
|
|
|
170
175
|
name="static",
|
|
171
176
|
)
|
|
172
177
|
|
|
173
|
-
|
|
174
|
-
def start_static_server() -> None:
|
|
175
|
-
"""Run uvicorn server synchronously using uvicorn.run."""
|
|
176
|
-
# Setup the FastAPI app
|
|
177
|
-
_setup_app()
|
|
178
|
-
|
|
179
178
|
try:
|
|
180
179
|
# Run server using uvicorn.run
|
|
181
180
|
uvicorn.run(
|
|
@@ -9,6 +9,18 @@ from griptape_nodes.retained_mode.events.app_events import (
|
|
|
9
9
|
GetEngineVersionResultSuccess,
|
|
10
10
|
)
|
|
11
11
|
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
12
|
+
from griptape_nodes.retained_mode.managers.fitness_problems.libraries.modified_parameters_set_deprecation_warning_problem import (
|
|
13
|
+
ModifiedParametersSetDeprecationWarningProblem,
|
|
14
|
+
)
|
|
15
|
+
from griptape_nodes.retained_mode.managers.fitness_problems.libraries.modified_parameters_set_removed_problem import (
|
|
16
|
+
ModifiedParametersSetRemovedProblem,
|
|
17
|
+
)
|
|
18
|
+
from griptape_nodes.retained_mode.managers.fitness_problems.libraries.ui_options_field_modified_incompatible_problem import (
|
|
19
|
+
UiOptionsFieldModifiedIncompatibleProblem,
|
|
20
|
+
)
|
|
21
|
+
from griptape_nodes.retained_mode.managers.fitness_problems.libraries.ui_options_field_modified_warning_problem import (
|
|
22
|
+
UiOptionsFieldModifiedWarningProblem,
|
|
23
|
+
)
|
|
12
24
|
from griptape_nodes.retained_mode.managers.library_lifecycle.library_status import LibraryStatus
|
|
13
25
|
from griptape_nodes.retained_mode.managers.version_compatibility_manager import (
|
|
14
26
|
LibraryVersionCompatibilityCheck,
|
|
@@ -49,15 +61,11 @@ class ModifiedParametersSetRemovalCheck(LibraryVersionCompatibilityCheck):
|
|
|
49
61
|
# 0.39+ Release: Parameter removed, reject incompatible libraries
|
|
50
62
|
return [
|
|
51
63
|
LibraryVersionCompatibilityIssue(
|
|
52
|
-
|
|
53
|
-
"The 'modified_parameters_set' parameter has been removed from BaseNode methods: 'after_incoming_connection', 'after_outgoing_connection', 'after_incoming_connection_removed', 'after_outgoing_connection_removed', 'before_value_set', and 'after_value_set'. "
|
|
54
|
-
"If this library overrides any of these methods, it will not load or function properly. Please update to a newer version of this library or contact the library author immediately.",
|
|
64
|
+
problem=ModifiedParametersSetRemovedProblem(library_engine_version=library_version_str),
|
|
55
65
|
severity=LibraryStatus.UNUSABLE,
|
|
56
66
|
),
|
|
57
67
|
LibraryVersionCompatibilityIssue(
|
|
58
|
-
|
|
59
|
-
"The 'ui_options' field has been modified on all Elements. In order to function properly, all nodes must update ui_options by setting its value to a new dictionary. Updating ui_options by accessing the private field _ui_options will no longer create UI updates in the editor."
|
|
60
|
-
"If this library accesses the private _ui_options field, it will not update the editor properly. Please update to a newer version of this library or contact the library author immediately.",
|
|
68
|
+
problem=UiOptionsFieldModifiedIncompatibleProblem(library_engine_version=library_version_str),
|
|
61
69
|
severity=LibraryStatus.UNUSABLE,
|
|
62
70
|
),
|
|
63
71
|
]
|
|
@@ -65,15 +73,11 @@ class ModifiedParametersSetRemovalCheck(LibraryVersionCompatibilityCheck):
|
|
|
65
73
|
# 0.38 Release: Warning about upcoming removal in 0.39
|
|
66
74
|
return [
|
|
67
75
|
LibraryVersionCompatibilityIssue(
|
|
68
|
-
|
|
69
|
-
f"This library (built for engine version {library_version_str}) must be updated before the 0.39 release. "
|
|
70
|
-
"If this library overrides any of these methods, it will fail to load in 0.39. If not, no action is necessary. Please contact the library author to confirm whether this library is impacted.",
|
|
76
|
+
problem=ModifiedParametersSetDeprecationWarningProblem(library_engine_version=library_version_str),
|
|
71
77
|
severity=LibraryStatus.FLAWED,
|
|
72
78
|
),
|
|
73
79
|
LibraryVersionCompatibilityIssue(
|
|
74
|
-
|
|
75
|
-
"In order to function properly, all nodes must update ui_options by setting its value to a new dictionary. Updating ui_options by accessing the private field _ui_options will no longer create UI updates in the editor."
|
|
76
|
-
"If this library accesses the private _ui_options field, it will not update the editor properly. Please update to a newer version of this library or contact the library author immediately.",
|
|
80
|
+
problem=UiOptionsFieldModifiedWarningProblem(),
|
|
77
81
|
severity=LibraryStatus.FLAWED,
|
|
78
82
|
),
|
|
79
83
|
]
|
griptape_nodes/version_compatibility/workflow_versions/v0_7_0/local_executor_argument_addition.py
CHANGED
|
@@ -6,6 +6,9 @@ from typing import TYPE_CHECKING
|
|
|
6
6
|
|
|
7
7
|
import semver
|
|
8
8
|
|
|
9
|
+
from griptape_nodes.retained_mode.managers.fitness_problems.workflows.workflow_schema_version_problem import (
|
|
10
|
+
WorkflowSchemaVersionProblem,
|
|
11
|
+
)
|
|
9
12
|
from griptape_nodes.retained_mode.managers.version_compatibility_manager import (
|
|
10
13
|
WorkflowVersionCompatibilityCheck,
|
|
11
14
|
WorkflowVersionCompatibilityIssue,
|
|
@@ -39,9 +42,9 @@ class LocalExecutorArgumentAddition(WorkflowVersionCompatibilityCheck):
|
|
|
39
42
|
if workflow_schema_version < semver.VersionInfo(0, 7, 0):
|
|
40
43
|
issues.append(
|
|
41
44
|
WorkflowVersionCompatibilityIssue(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
problem=WorkflowSchemaVersionProblem(
|
|
46
|
+
description=f"Schema version {workflow_metadata.schema_version} older than 0.7.0. This workflow may not publish or execute properly. Re-save workflow to update."
|
|
47
|
+
),
|
|
45
48
|
severity=WorkflowManager.WorkflowStatus.FLAWED,
|
|
46
49
|
)
|
|
47
50
|
)
|