griptape-nodes 0.46.0__py3-none-any.whl → 0.47.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.
Files changed (23) hide show
  1. griptape_nodes/exe_types/core_types.py +65 -10
  2. griptape_nodes/exe_types/node_types.py +10 -0
  3. griptape_nodes/machines/node_resolution.py +10 -8
  4. griptape_nodes/retained_mode/events/base_events.py +74 -1
  5. griptape_nodes/retained_mode/events/secrets_events.py +2 -0
  6. griptape_nodes/retained_mode/griptape_nodes.py +17 -13
  7. griptape_nodes/retained_mode/managers/agent_manager.py +8 -6
  8. griptape_nodes/retained_mode/managers/arbitrary_code_exec_manager.py +1 -1
  9. griptape_nodes/retained_mode/managers/config_manager.py +36 -45
  10. griptape_nodes/retained_mode/managers/flow_manager.py +98 -98
  11. griptape_nodes/retained_mode/managers/library_manager.py +51 -51
  12. griptape_nodes/retained_mode/managers/node_manager.py +121 -124
  13. griptape_nodes/retained_mode/managers/object_manager.py +9 -10
  14. griptape_nodes/retained_mode/managers/os_manager.py +31 -31
  15. griptape_nodes/retained_mode/managers/secrets_manager.py +5 -5
  16. griptape_nodes/retained_mode/managers/static_files_manager.py +18 -17
  17. griptape_nodes/retained_mode/managers/sync_manager.py +3 -2
  18. griptape_nodes/retained_mode/managers/workflow_manager.py +134 -160
  19. griptape_nodes/retained_mode/retained_mode.py +22 -44
  20. {griptape_nodes-0.46.0.dist-info → griptape_nodes-0.47.0.dist-info}/METADATA +1 -1
  21. {griptape_nodes-0.46.0.dist-info → griptape_nodes-0.47.0.dist-info}/RECORD +23 -23
  22. {griptape_nodes-0.46.0.dist-info → griptape_nodes-0.47.0.dist-info}/WHEEL +1 -1
  23. {griptape_nodes-0.46.0.dist-info → griptape_nodes-0.47.0.dist-info}/entry_points.txt +0 -0
@@ -253,7 +253,7 @@ class FlowManager:
253
253
  if not GriptapeNodes.ContextManager().has_current_flow():
254
254
  details = "Attempted to get Flow details from the Current Context. Failed because the Current Context was empty."
255
255
  logger.error(details)
256
- return GetFlowDetailsResultFailure()
256
+ return GetFlowDetailsResultFailure(result_details=details)
257
257
  flow = GriptapeNodes.ContextManager().get_current_flow()
258
258
  flow_name = flow.name
259
259
  else:
@@ -263,14 +263,14 @@ class FlowManager:
263
263
  f"Attempted to get Flow details for '{flow_name}'. Failed because no Flow with that name exists."
264
264
  )
265
265
  logger.error(details)
266
- return GetFlowDetailsResultFailure()
266
+ return GetFlowDetailsResultFailure(result_details=details)
267
267
 
268
268
  try:
269
269
  parent_flow_name = self.get_parent_flow(flow_name)
270
270
  except ValueError:
271
271
  details = f"Attempted to get Flow details for '{flow_name}'. Failed because Flow does not exist in parent mapping."
272
272
  logger.error(details)
273
- return GetFlowDetailsResultFailure()
273
+ return GetFlowDetailsResultFailure(result_details=details)
274
274
 
275
275
  referenced_workflow_name = None
276
276
  if self.is_referenced_workflow(flow):
@@ -291,7 +291,7 @@ class FlowManager:
291
291
  if not GriptapeNodes.ContextManager().has_current_flow():
292
292
  details = "Attempted to get metadata for a Flow from the Current Context. Failed because the Current Context is empty."
293
293
  logger.error(details)
294
- return GetFlowMetadataResultFailure()
294
+ return GetFlowMetadataResultFailure(result_details=details)
295
295
 
296
296
  flow = GriptapeNodes.ContextManager().get_current_flow()
297
297
  flow_name = flow.name
@@ -303,7 +303,7 @@ class FlowManager:
303
303
  if flow is None:
304
304
  details = f"Attempted to get metadata for a Flow '{flow_name}', but no such Flow was found."
305
305
  logger.error(details)
306
- return GetFlowMetadataResultFailure()
306
+ return GetFlowMetadataResultFailure(result_details=details)
307
307
 
308
308
  metadata = flow.metadata
309
309
  details = f"Successfully retrieved metadata for a Flow '{flow_name}'."
@@ -319,7 +319,7 @@ class FlowManager:
319
319
  if not GriptapeNodes.ContextManager().has_current_flow():
320
320
  details = "Attempted to set metadata for a Flow from the Current Context. Failed because the Current Context is empty."
321
321
  logger.error(details)
322
- return SetFlowMetadataResultFailure()
322
+ return SetFlowMetadataResultFailure(result_details=details)
323
323
 
324
324
  flow = GriptapeNodes.ContextManager().get_current_flow()
325
325
  flow_name = flow.name
@@ -331,7 +331,7 @@ class FlowManager:
331
331
  if flow is None:
332
332
  details = f"Attempted to set metadata for a Flow '{flow_name}', but no such Flow was found."
333
333
  logger.error(details)
334
- return SetFlowMetadataResultFailure()
334
+ return SetFlowMetadataResultFailure(result_details=details)
335
335
 
336
336
  # We can't completely overwrite metadata.
337
337
  for key, value in request.metadata.items():
@@ -370,14 +370,14 @@ class FlowManager:
370
370
  # We're trying to create the canvas. Ensure that parent does NOT already exist.
371
371
  details = "Attempted to create a Flow as the Canvas (top-level Flow with no parents), but the Canvas already exists."
372
372
  logger.error(details)
373
- result = CreateFlowResultFailure()
373
+ result = CreateFlowResultFailure(result_details=details)
374
374
  return result
375
375
  # Now our parent exists, right?
376
376
  elif parent is None:
377
377
  details = f"Attempted to create a Flow with a parent '{request.parent_flow_name}', but no parent with that name could be found."
378
378
  logger.error(details)
379
379
 
380
- result = CreateFlowResultFailure()
380
+ result = CreateFlowResultFailure(result_details=details)
381
381
 
382
382
  return result
383
383
 
@@ -385,7 +385,7 @@ class FlowManager:
385
385
  if not GriptapeNodes.ContextManager().has_current_workflow():
386
386
  details = "Attempted to create a Flow, but no Workflow was active in the Current Context."
387
387
  logger.error(details)
388
- return CreateFlowResultFailure()
388
+ return CreateFlowResultFailure(result_details=details)
389
389
 
390
390
  # Create it.
391
391
  final_flow_name = GriptapeNodes.ObjectManager().generate_name_for_object(
@@ -430,7 +430,7 @@ class FlowManager:
430
430
  "Attempted to delete a Flow from the Current Context. Failed because the Current Context was empty."
431
431
  )
432
432
  logger.error(details)
433
- result = DeleteFlowResultFailure()
433
+ result = DeleteFlowResultFailure(result_details=details)
434
434
  return result
435
435
  # We pop it off here, but we'll re-add it using context in a moment.
436
436
  flow = GriptapeNodes.ContextManager().pop_flow()
@@ -442,14 +442,14 @@ class FlowManager:
442
442
  if flow is None:
443
443
  details = f"Attempted to delete Flow '{flow_name}', but no Flow with that name could be found."
444
444
  logger.error(details)
445
- result = DeleteFlowResultFailure()
445
+ result = DeleteFlowResultFailure(result_details=details)
446
446
  return result
447
447
  if self.check_for_existing_running_flow():
448
448
  result = GriptapeNodes.handle_request(CancelFlowRequest(flow_name=flow.name))
449
449
  if not result.succeeded():
450
450
  details = f"Attempted to delete flow '{flow_name}'. Failed because running flow could not cancel."
451
451
  logger.error(details)
452
- return DeleteFlowResultFailure()
452
+ return DeleteFlowResultFailure(result_details=details)
453
453
 
454
454
  # Let this Flow assume the Current Context while we delete everything within it.
455
455
  with GriptapeNodes.ContextManager().flow(flow=flow):
@@ -459,7 +459,7 @@ class FlowManager:
459
459
  if not isinstance(list_nodes_result, ListNodesInFlowResultSuccess):
460
460
  details = f"Attempted to delete Flow '{flow.name}', but failed while attempting to get the list of Nodes owned by this Flow."
461
461
  logger.error(details)
462
- result = DeleteFlowResultFailure()
462
+ result = DeleteFlowResultFailure(result_details=details)
463
463
  return result
464
464
  node_names = list_nodes_result.node_names
465
465
  for node_name in node_names:
@@ -468,7 +468,7 @@ class FlowManager:
468
468
  if isinstance(delete_node_result, DeleteNodeResultFailure):
469
469
  details = f"Attempted to delete Flow '{flow.name}', but failed while attempting to delete child Node '{node_name}'."
470
470
  logger.error(details)
471
- result = DeleteFlowResultFailure()
471
+ result = DeleteFlowResultFailure(result_details=details)
472
472
  return result
473
473
 
474
474
  # Delete all child Flows of this Flow.
@@ -480,7 +480,7 @@ class FlowManager:
480
480
  if not isinstance(list_flows_result, ListFlowsInCurrentContextResultSuccess):
481
481
  details = f"Attempted to delete Flow '{flow_name}', but failed while attempting to get the list of Flows owned by this Flow."
482
482
  logger.error(details)
483
- result = DeleteFlowResultFailure()
483
+ result = DeleteFlowResultFailure(result_details=details)
484
484
  return result
485
485
  flow_names = list_flows_result.flow_names
486
486
  obj_mgr = GriptapeNodes.ObjectManager()
@@ -491,7 +491,7 @@ class FlowManager:
491
491
  f"Attempted to delete Flow '{child_flow_name}', but no Flow with that name could be found."
492
492
  )
493
493
  logger.error(details)
494
- result = DeleteFlowResultFailure()
494
+ result = DeleteFlowResultFailure(result_details=details)
495
495
  return result
496
496
  with GriptapeNodes.ContextManager().flow(flow=child_flow):
497
497
  # Delete them.
@@ -500,7 +500,7 @@ class FlowManager:
500
500
  if isinstance(delete_flow_result, DeleteFlowResultFailure):
501
501
  details = f"Attempted to delete Flow '{flow.name}', but failed while attempting to delete child Flow '{child_flow.name}'."
502
502
  logger.error(details)
503
- result = DeleteFlowResultFailure()
503
+ result = DeleteFlowResultFailure(result_details=details)
504
504
  return result
505
505
 
506
506
  # If we've made it this far, we have deleted all the children Flows and their nodes.
@@ -522,19 +522,19 @@ class FlowManager:
522
522
  if request.flow_name is None:
523
523
  details = "Attempted to get Flow, but no flow name was provided."
524
524
  logger.error(details)
525
- return GetIsFlowRunningResultFailure()
525
+ return GetIsFlowRunningResultFailure(result_details=details)
526
526
  flow = obj_mgr.attempt_get_object_by_name_as_type(request.flow_name, ControlFlow)
527
527
  if flow is None:
528
528
  details = f"Attempted to get Flow '{request.flow_name}', but no Flow with that name could be found."
529
529
  logger.error(details)
530
- result = GetIsFlowRunningResultFailure()
530
+ result = GetIsFlowRunningResultFailure(result_details=details)
531
531
  return result
532
532
  try:
533
533
  is_running = self.check_for_existing_running_flow()
534
534
  except Exception:
535
535
  details = f"Error while trying to get status of '{request.flow_name}'."
536
536
  logger.error(details)
537
- result = GetIsFlowRunningResultFailure()
537
+ result = GetIsFlowRunningResultFailure(result_details=details)
538
538
  return result
539
539
  return GetIsFlowRunningResultSuccess(is_running=is_running)
540
540
 
@@ -546,7 +546,7 @@ class FlowManager:
546
546
  if not GriptapeNodes.ContextManager().has_current_flow():
547
547
  details = "Attempted to list Nodes in a Flow in the Current Context. Failed because the Current Context was empty."
548
548
  logger.error(details)
549
- result = ListNodesInFlowResultFailure()
549
+ result = ListNodesInFlowResultFailure(result_details=details)
550
550
  return result
551
551
  # Get the current flow from context
552
552
  flow = GriptapeNodes.ContextManager().get_current_flow()
@@ -560,7 +560,7 @@ class FlowManager:
560
560
  f"Attempted to list Nodes in Flow '{flow_name}'. Failed because no Flow with that name could be found."
561
561
  )
562
562
  logger.error(details)
563
- result = ListNodesInFlowResultFailure()
563
+ result = ListNodesInFlowResultFailure(result_details=details)
564
564
  return result
565
565
 
566
566
  ret_list = list(flow.nodes.keys())
@@ -578,7 +578,7 @@ class FlowManager:
578
578
  if flow is None:
579
579
  details = f"Attempted to list Flows that are children of Flow '{request.parent_flow_name}', but no Flow with that name could be found."
580
580
  logger.error(details)
581
- result = ListFlowsInFlowResultFailure()
581
+ result = ListFlowsInFlowResultFailure(result_details=details)
582
582
  return result
583
583
 
584
584
  # Create a list of all child flow names that point DIRECTLY to us.
@@ -625,7 +625,7 @@ class FlowManager:
625
625
  if not GriptapeNodes.ContextManager().has_current_node():
626
626
  details = "Attempted to create a Connection with a source node from the Current Context. Failed because the Current Context was empty."
627
627
  logger.error(details)
628
- return CreateConnectionResultFailure()
628
+ return CreateConnectionResultFailure(result_details=details)
629
629
 
630
630
  # Get the current node from context
631
631
  source_node = GriptapeNodes.ContextManager().get_current_node()
@@ -637,7 +637,7 @@ class FlowManager:
637
637
  details = f'Connection failed: "{source_node_name}" does not exist. Error: {err}.'
638
638
  logger.error(details)
639
639
 
640
- return CreateConnectionResultFailure()
640
+ return CreateConnectionResultFailure(result_details=details)
641
641
 
642
642
  target_node_name = request.target_node_name
643
643
  target_node = None
@@ -646,7 +646,7 @@ class FlowManager:
646
646
  if not GriptapeNodes.ContextManager().has_current_node():
647
647
  details = "Attempted to create a Connection with the target node from the Current Context. Failed because the Current Context was empty."
648
648
  logger.error(details)
649
- return CreateConnectionResultFailure()
649
+ return CreateConnectionResultFailure(result_details=details)
650
650
 
651
651
  # Get the current node from context
652
652
  target_node = GriptapeNodes.ContextManager().get_current_node()
@@ -657,7 +657,7 @@ class FlowManager:
657
657
  except ValueError as err:
658
658
  details = f'Connection failed: "{target_node_name}" does not exist. Error: {err}.'
659
659
  logger.error(details)
660
- return CreateConnectionResultFailure()
660
+ return CreateConnectionResultFailure(result_details=details)
661
661
 
662
662
  # The two nodes exist.
663
663
  # Get the parent flows.
@@ -668,7 +668,7 @@ class FlowManager:
668
668
  except KeyError as err:
669
669
  details = f'Connection "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}" failed: {err}.'
670
670
  logger.error(details)
671
- return CreateConnectionResultFailure()
671
+ return CreateConnectionResultFailure(result_details=details)
672
672
 
673
673
  target_flow_name = None
674
674
  try:
@@ -677,7 +677,7 @@ class FlowManager:
677
677
  except KeyError as err:
678
678
  details = f'Connection "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}" failed: {err}.'
679
679
  logger.error(details)
680
- return CreateConnectionResultFailure()
680
+ return CreateConnectionResultFailure(result_details=details)
681
681
 
682
682
  # Cross-flow connections are now supported via global connection storage
683
683
 
@@ -686,14 +686,14 @@ class FlowManager:
686
686
  if source_param is None:
687
687
  details = f'Connection failed: "{source_node_name}.{request.source_parameter_name}" not found'
688
688
  logger.error(details)
689
- return CreateConnectionResultFailure()
689
+ return CreateConnectionResultFailure(result_details=details)
690
690
 
691
691
  target_param = target_node.get_parameter_by_name(request.target_parameter_name)
692
692
  if target_param is None:
693
693
  # TODO: https://github.com/griptape-ai/griptape-nodes/issues/860
694
694
  details = f'Connection failed: "{target_node_name}.{request.target_parameter_name}" not found'
695
695
  logger.error(details)
696
- return CreateConnectionResultFailure()
696
+ return CreateConnectionResultFailure(result_details=details)
697
697
  # Validate parameter modes accept this type of connection.
698
698
  source_modes_allowed = source_param.allowed_modes
699
699
  if ParameterMode.OUTPUT not in source_modes_allowed:
@@ -701,19 +701,19 @@ class FlowManager:
701
701
  f'Connection failed: "{source_node_name}.{request.source_parameter_name}" is not an allowed OUTPUT'
702
702
  )
703
703
  logger.error(details)
704
- return CreateConnectionResultFailure()
704
+ return CreateConnectionResultFailure(result_details=details)
705
705
 
706
706
  target_modes_allowed = target_param.allowed_modes
707
707
  if ParameterMode.INPUT not in target_modes_allowed:
708
708
  details = f'Connection failed: "{target_node_name}.{request.target_parameter_name}" is not an allowed INPUT'
709
709
  logger.error(details)
710
- return CreateConnectionResultFailure()
710
+ return CreateConnectionResultFailure(result_details=details)
711
711
 
712
712
  # Validate that the data type from the source is allowed by the target.
713
713
  if not target_param.is_incoming_type_allowed(source_param.output_type):
714
714
  details = f'Connection failed on type mismatch "{source_node_name}.{request.source_parameter_name}" type({source_param.output_type}) to "{target_node_name}.{request.target_parameter_name}" types({target_param.input_types}) '
715
715
  logger.error(details)
716
- return CreateConnectionResultFailure()
716
+ return CreateConnectionResultFailure(result_details=details)
717
717
 
718
718
  # Ask each node involved to bless this union.
719
719
  if not source_node.allow_outgoing_connection(
@@ -725,7 +725,7 @@ class FlowManager:
725
725
  f'Connection failed : "{source_node_name}.{request.source_parameter_name}" rejected the connection '
726
726
  )
727
727
  logger.error(details)
728
- return CreateConnectionResultFailure()
728
+ return CreateConnectionResultFailure(result_details=details)
729
729
 
730
730
  if not target_node.allow_incoming_connection(
731
731
  source_node=source_node,
@@ -736,7 +736,7 @@ class FlowManager:
736
736
  f'Connection failed : "{target_node_name}.{request.target_parameter_name}" rejected the connection '
737
737
  )
738
738
  logger.error(details)
739
- return CreateConnectionResultFailure()
739
+ return CreateConnectionResultFailure(result_details=details)
740
740
 
741
741
  # Based on user feedback, if a connection already exists in a scenario where only ONE such connection can exist
742
742
  # (e.g., connecting to a data input that already has a connection, or from a control output that is already wired up),
@@ -776,7 +776,7 @@ class FlowManager:
776
776
  if delete_old_result.failed():
777
777
  details = f"Attempted to connect '{source_node_name}.{request.source_parameter_name}'. Failed because there was a previous connection from '{old_source_node_name}.{old_source_param_name}' to '{old_target_node_name}.{old_target_param_name}' that could not be deleted."
778
778
  logger.error(details)
779
- return CreateConnectionResultFailure()
779
+ return CreateConnectionResultFailure(result_details=details)
780
780
 
781
781
  details = f"Deleted the previous connection from '{old_source_node_name}.{old_source_param_name}' to '{old_target_node_name}.{old_target_param_name}' to make room for the new connection."
782
782
  logger.debug(details)
@@ -810,7 +810,7 @@ class FlowManager:
810
810
  if create_old_connection_result.failed():
811
811
  details = "Failed attempting to restore the old Connection after failing the replacement. A thousand pardons."
812
812
  logger.error(details)
813
- return CreateConnectionResultFailure()
813
+ return CreateConnectionResultFailure(result_details=details)
814
814
 
815
815
  # Let the source make any internal handling decisions now that the Connection has been made.
816
816
  source_node.after_outgoing_connection(
@@ -867,7 +867,7 @@ class FlowManager:
867
867
  if not GriptapeNodes.ContextManager().has_current_node():
868
868
  details = "Attempted to delete a Connection with a source node from the Current Context. Failed because the Current Context was empty."
869
869
  logger.error(details)
870
- return DeleteConnectionResultFailure()
870
+ return DeleteConnectionResultFailure(result_details=details)
871
871
 
872
872
  # Get the current node from context
873
873
  source_node = GriptapeNodes.ContextManager().get_current_node()
@@ -879,7 +879,7 @@ class FlowManager:
879
879
  details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
880
880
  logger.error(details)
881
881
 
882
- return DeleteConnectionResultFailure()
882
+ return DeleteConnectionResultFailure(result_details=details)
883
883
 
884
884
  target_node_name = request.target_node_name
885
885
  if target_node_name is None:
@@ -887,7 +887,7 @@ class FlowManager:
887
887
  if not GriptapeNodes.ContextManager().has_current_node():
888
888
  details = "Attempted to delete a Connection with a target node from the Current Context. Failed because the Current Context was empty."
889
889
  logger.error(details)
890
- return DeleteConnectionResultFailure()
890
+ return DeleteConnectionResultFailure(result_details=details)
891
891
 
892
892
  # Get the current node from context
893
893
  target_node = GriptapeNodes.ContextManager().get_current_node()
@@ -899,7 +899,7 @@ class FlowManager:
899
899
  details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
900
900
  logger.error(details)
901
901
 
902
- return DeleteConnectionResultFailure()
902
+ return DeleteConnectionResultFailure(result_details=details)
903
903
 
904
904
  # The two nodes exist.
905
905
  # Get the parent flows.
@@ -911,7 +911,7 @@ class FlowManager:
911
911
  details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
912
912
  logger.error(details)
913
913
 
914
- return DeleteConnectionResultFailure()
914
+ return DeleteConnectionResultFailure(result_details=details)
915
915
 
916
916
  target_flow_name = None
917
917
  try:
@@ -921,7 +921,7 @@ class FlowManager:
921
921
  details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
922
922
  logger.error(details)
923
923
 
924
- return DeleteConnectionResultFailure()
924
+ return DeleteConnectionResultFailure(result_details=details)
925
925
 
926
926
  # Cross-flow connections are now supported via global connection storage
927
927
 
@@ -931,14 +931,14 @@ class FlowManager:
931
931
  details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" Not found.'
932
932
  logger.error(details)
933
933
 
934
- return DeleteConnectionResultFailure()
934
+ return DeleteConnectionResultFailure(result_details=details)
935
935
 
936
936
  target_param = target_node.get_parameter_by_name(request.target_parameter_name)
937
937
  if target_param is None:
938
938
  details = f'Connection not deleted "{target_node_name}.{request.target_parameter_name}" Not found.'
939
939
  logger.error(details)
940
940
 
941
- return DeleteConnectionResultFailure()
941
+ return DeleteConnectionResultFailure(result_details=details)
942
942
 
943
943
  # Vet that a Connection actually exists between them already.
944
944
  if not self._has_connection(
@@ -950,7 +950,7 @@ class FlowManager:
950
950
  details = f'Connection does not exist: "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}"'
951
951
  logger.error(details)
952
952
 
953
- return DeleteConnectionResultFailure()
953
+ return DeleteConnectionResultFailure(result_details=details)
954
954
 
955
955
  # Remove the connection.
956
956
  if not self._connections.remove_connection(
@@ -962,7 +962,7 @@ class FlowManager:
962
962
  details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Unknown failure.'
963
963
  logger.error(details)
964
964
 
965
- return DeleteConnectionResultFailure()
965
+ return DeleteConnectionResultFailure(result_details=details)
966
966
 
967
967
  # After the connection has been removed, if it doesn't have PROPERTY as a type, wipe the set parameter value and unresolve future nodes
968
968
  if ParameterMode.PROPERTY not in target_param.allowed_modes:
@@ -1006,19 +1006,19 @@ class FlowManager:
1006
1006
  details = "Must provide flow name to start a flow."
1007
1007
  logger.error(details)
1008
1008
 
1009
- return StartFlowResultFailure(validation_exceptions=[])
1009
+ return StartFlowResultFailure(validation_exceptions=[], result_details=details)
1010
1010
  # get the flow by ID
1011
1011
  try:
1012
1012
  flow = self.get_flow_by_name(flow_name)
1013
1013
  except KeyError as err:
1014
1014
  details = f"Cannot start flow. Error: {err}"
1015
1015
  logger.error(details)
1016
- return StartFlowResultFailure(validation_exceptions=[err])
1016
+ return StartFlowResultFailure(validation_exceptions=[err], result_details=details)
1017
1017
  # Check to see if the flow is already running.
1018
1018
  if self.check_for_existing_running_flow():
1019
1019
  details = "Cannot start flow. Flow is already running."
1020
1020
  logger.error(details)
1021
- return StartFlowResultFailure(validation_exceptions=[])
1021
+ return StartFlowResultFailure(validation_exceptions=[], result_details=details)
1022
1022
  # A node has been provided to either start or to run up to.
1023
1023
  if request.flow_node_name:
1024
1024
  flow_node_name = request.flow_node_name
@@ -1026,14 +1026,14 @@ class FlowManager:
1026
1026
  if not flow_node:
1027
1027
  details = f"Provided node with name {flow_node_name} does not exist"
1028
1028
  logger.error(details)
1029
- return StartFlowResultFailure(validation_exceptions=[])
1029
+ return StartFlowResultFailure(validation_exceptions=[], result_details=details)
1030
1030
  # lets get the first control node in the flow!
1031
1031
  start_node = self.get_start_node_from_node(flow, flow_node)
1032
1032
  # if the start is not the node provided, set a breakpoint at the stop (we're running up until there)
1033
1033
  if not start_node:
1034
1034
  details = f"Start node for node with name {flow_node_name} does not exist"
1035
1035
  logger.error(details)
1036
- return StartFlowResultFailure(validation_exceptions=[])
1036
+ return StartFlowResultFailure(validation_exceptions=[], result_details=details)
1037
1037
  if start_node != flow_node:
1038
1038
  flow_node.stop_flow = True
1039
1039
  else:
@@ -1058,18 +1058,18 @@ class FlowManager:
1058
1058
  for exception in result.exceptions:
1059
1059
  details = f"{details}\n\t{exception}"
1060
1060
  logger.error(details)
1061
- return StartFlowResultFailure(validation_exceptions=result.exceptions)
1061
+ return StartFlowResultFailure(validation_exceptions=result.exceptions, result_details=details)
1062
1062
  except Exception as e:
1063
1063
  details = f"Couldn't start flow with name {flow_name}. Flow Validation Failed: {e}"
1064
1064
  logger.error(details)
1065
- return StartFlowResultFailure(validation_exceptions=[e])
1065
+ return StartFlowResultFailure(validation_exceptions=[e], result_details=details)
1066
1066
  # By now, it has been validated with no exceptions.
1067
1067
  try:
1068
1068
  self.start_flow(flow, start_node, debug_mode)
1069
1069
  except Exception as e:
1070
1070
  details = f"Failed to kick off flow with name {flow_name}. Exception occurred: {e} "
1071
1071
  logger.error(details)
1072
- return StartFlowResultFailure(validation_exceptions=[e])
1072
+ return StartFlowResultFailure(validation_exceptions=[e], result_details=details)
1073
1073
 
1074
1074
  details = f"Successfully kicked off flow with name {flow_name}"
1075
1075
  logger.debug(details)
@@ -1081,19 +1081,19 @@ class FlowManager:
1081
1081
  if not flow_name:
1082
1082
  details = "Could not get flow state. No flow name was provided."
1083
1083
  logger.error(details)
1084
- return GetFlowStateResultFailure()
1084
+ return GetFlowStateResultFailure(result_details=details)
1085
1085
  try:
1086
1086
  flow = self.get_flow_by_name(flow_name)
1087
1087
  except KeyError as err:
1088
1088
  details = f"Could not get flow state. Error: {err}"
1089
1089
  logger.error(details)
1090
- return GetFlowStateResultFailure()
1090
+ return GetFlowStateResultFailure(result_details=details)
1091
1091
  try:
1092
1092
  control_node, resolving_node = self.flow_state(flow)
1093
1093
  except Exception as e:
1094
1094
  details = f"Failed to get flow state of flow with name {flow_name}. Exception occurred: {e} "
1095
1095
  logger.exception(details)
1096
- return GetFlowStateResultFailure()
1096
+ return GetFlowStateResultFailure(result_details=details)
1097
1097
  details = f"Successfully got flow state for flow with name {flow_name}."
1098
1098
  logger.debug(details)
1099
1099
  return GetFlowStateResultSuccess(control_node=control_node, resolving_node=resolving_node)
@@ -1104,21 +1104,21 @@ class FlowManager:
1104
1104
  details = "Could not cancel flow execution. No flow name was provided."
1105
1105
  logger.error(details)
1106
1106
 
1107
- return CancelFlowResultFailure()
1107
+ return CancelFlowResultFailure(result_details=details)
1108
1108
  try:
1109
1109
  self.get_flow_by_name(flow_name)
1110
1110
  except KeyError as err:
1111
1111
  details = f"Could not cancel flow execution. Error: {err}"
1112
1112
  logger.error(details)
1113
1113
 
1114
- return CancelFlowResultFailure()
1114
+ return CancelFlowResultFailure(result_details=details)
1115
1115
  try:
1116
1116
  self.cancel_flow_run()
1117
1117
  except Exception as e:
1118
1118
  details = f"Could not cancel flow execution. Exception: {e}"
1119
1119
  logger.error(details)
1120
1120
 
1121
- return CancelFlowResultFailure()
1121
+ return CancelFlowResultFailure(result_details=details)
1122
1122
  details = f"Successfully cancelled flow execution with name {flow_name}"
1123
1123
  logger.debug(details)
1124
1124
 
@@ -1130,21 +1130,21 @@ class FlowManager:
1130
1130
  details = "Could not advance to the next step of a running workflow. No flow name was provided."
1131
1131
  logger.error(details)
1132
1132
 
1133
- return SingleNodeStepResultFailure(validation_exceptions=[])
1133
+ return SingleNodeStepResultFailure(validation_exceptions=[], result_details=details)
1134
1134
  try:
1135
1135
  self.get_flow_by_name(flow_name)
1136
1136
  except KeyError as err:
1137
1137
  details = f"Could not advance to the next step of a running workflow. No flow with name {flow_name} exists. Error: {err}"
1138
1138
  logger.error(details)
1139
1139
 
1140
- return SingleNodeStepResultFailure(validation_exceptions=[err])
1140
+ return SingleNodeStepResultFailure(validation_exceptions=[err], result_details=details)
1141
1141
  try:
1142
1142
  flow = self.get_flow_by_name(flow_name)
1143
1143
  self.single_node_step(flow)
1144
1144
  except Exception as e:
1145
1145
  details = f"Could not advance to the next step of a running workflow. Exception: {e}"
1146
1146
  logger.error(details)
1147
- return SingleNodeStepResultFailure(validation_exceptions=[])
1147
+ return SingleNodeStepResultFailure(validation_exceptions=[], result_details=details)
1148
1148
 
1149
1149
  # All completed happily
1150
1150
  details = f"Successfully advanced to the next step of a running workflow with name {flow_name}"
@@ -1158,14 +1158,14 @@ class FlowManager:
1158
1158
  details = "Could not advance to the next step of a running workflow. No flow name was provided."
1159
1159
  logger.error(details)
1160
1160
 
1161
- return SingleExecutionStepResultFailure()
1161
+ return SingleExecutionStepResultFailure(result_details=details)
1162
1162
  try:
1163
1163
  flow = self.get_flow_by_name(flow_name)
1164
1164
  except KeyError as err:
1165
1165
  details = f"Could not advance to the next step of a running workflow. Error: {err}."
1166
1166
  logger.error(details)
1167
1167
 
1168
- return SingleExecutionStepResultFailure()
1168
+ return SingleExecutionStepResultFailure(result_details=details)
1169
1169
  change_debug_mode = request.request_id is not None
1170
1170
  try:
1171
1171
  self.single_execution_step(flow, change_debug_mode)
@@ -1180,7 +1180,7 @@ class FlowManager:
1180
1180
 
1181
1181
  details = f"Could not advance to the next step of a running workflow. Exception: {e}"
1182
1182
  logger.error(details)
1183
- return SingleNodeStepResultFailure(validation_exceptions=[e])
1183
+ return SingleNodeStepResultFailure(validation_exceptions=[e], result_details=details)
1184
1184
  details = f"Successfully advanced to the next step of a running workflow with name {flow_name}"
1185
1185
  logger.debug(details)
1186
1186
 
@@ -1192,20 +1192,20 @@ class FlowManager:
1192
1192
  details = "Failed to continue execution step because no flow name was provided"
1193
1193
  logger.error(details)
1194
1194
 
1195
- return ContinueExecutionStepResultFailure()
1195
+ return ContinueExecutionStepResultFailure(result_details=details)
1196
1196
  try:
1197
1197
  flow = self.get_flow_by_name(flow_name)
1198
1198
  except KeyError as err:
1199
1199
  details = f"Failed to continue execution step. Error: {err}"
1200
1200
  logger.error(details)
1201
1201
 
1202
- return ContinueExecutionStepResultFailure()
1202
+ return ContinueExecutionStepResultFailure(result_details=details)
1203
1203
  try:
1204
1204
  self.continue_executing(flow)
1205
1205
  except Exception as e:
1206
1206
  details = f"Failed to continue execution step. An exception occurred: {e}."
1207
1207
  logger.error(details)
1208
- return ContinueExecutionStepResultFailure()
1208
+ return ContinueExecutionStepResultFailure(result_details=details)
1209
1209
  details = f"Successfully continued flow with name {flow_name}"
1210
1210
  logger.debug(details)
1211
1211
  return ContinueExecutionStepResultSuccess()
@@ -1215,19 +1215,19 @@ class FlowManager:
1215
1215
  if not flow_name:
1216
1216
  details = "Failed to unresolve flow because no flow name was provided"
1217
1217
  logger.error(details)
1218
- return UnresolveFlowResultFailure()
1218
+ return UnresolveFlowResultFailure(result_details=details)
1219
1219
  try:
1220
1220
  flow = self.get_flow_by_name(flow_name)
1221
1221
  except KeyError as err:
1222
1222
  details = f"Failed to unresolve flow. Error: {err}"
1223
1223
  logger.error(details)
1224
- return UnresolveFlowResultFailure()
1224
+ return UnresolveFlowResultFailure(result_details=details)
1225
1225
  try:
1226
1226
  self.unresolve_whole_flow(flow)
1227
1227
  except Exception as e:
1228
1228
  details = f"Failed to unresolve flow. An exception occurred: {e}."
1229
1229
  logger.error(details)
1230
- return UnresolveFlowResultFailure()
1230
+ return UnresolveFlowResultFailure(result_details=details)
1231
1231
  details = f"Unresolved flow with name {flow_name}"
1232
1232
  logger.debug(details)
1233
1233
  return UnresolveFlowResultSuccess()
@@ -1240,14 +1240,14 @@ class FlowManager:
1240
1240
  except KeyError as err:
1241
1241
  details = f"Failed to validate flow. Error: {err}"
1242
1242
  logger.error(details)
1243
- return ValidateFlowDependenciesResultFailure()
1243
+ return ValidateFlowDependenciesResultFailure(result_details=details)
1244
1244
  if request.flow_node_name:
1245
1245
  flow_node_name = request.flow_node_name
1246
1246
  flow_node = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(flow_node_name, BaseNode)
1247
1247
  if not flow_node:
1248
1248
  details = f"Provided node with name {flow_node_name} does not exist"
1249
1249
  logger.error(details)
1250
- return ValidateFlowDependenciesResultFailure()
1250
+ return ValidateFlowDependenciesResultFailure(result_details=details)
1251
1251
  # Gets all nodes in that connected group to be ran
1252
1252
  nodes = flow.get_all_connected_nodes(flow_node)
1253
1253
  else:
@@ -1266,7 +1266,7 @@ class FlowManager:
1266
1266
  if not GriptapeNodes.ContextManager().has_current_flow():
1267
1267
  details = "Attempted to list Flows in the Current Context. Failed because the Current Context was empty."
1268
1268
  logger.error(details)
1269
- return ListFlowsInCurrentContextResultFailure()
1269
+ return ListFlowsInCurrentContextResultFailure(result_details=details)
1270
1270
 
1271
1271
  parent_flow = GriptapeNodes.ContextManager().get_current_flow()
1272
1272
  parent_flow_name = parent_flow.name
@@ -1294,7 +1294,7 @@ class FlowManager:
1294
1294
  else:
1295
1295
  details = "Attempted to serialize a Flow to commands from the Current Context. Failed because the Current Context was empty."
1296
1296
  logger.error(details)
1297
- return SerializeFlowToCommandsResultFailure()
1297
+ return SerializeFlowToCommandsResultFailure(result_details=details)
1298
1298
  if flow is None:
1299
1299
  # Does this flow exist?
1300
1300
  flow = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(flow_name, ControlFlow)
@@ -1303,7 +1303,7 @@ class FlowManager:
1303
1303
  f"Attempted to serialize Flow '{flow_name}' to commands, but no Flow with that name could be found."
1304
1304
  )
1305
1305
  logger.error(details)
1306
- return SerializeFlowToCommandsResultFailure()
1306
+ return SerializeFlowToCommandsResultFailure(result_details=details)
1307
1307
 
1308
1308
  # Track all node libraries that were in use by these Nodes
1309
1309
  node_libraries_in_use = set()
@@ -1349,7 +1349,7 @@ class FlowManager:
1349
1349
  f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to list Nodes in the Flow."
1350
1350
  )
1351
1351
  logger.error(details)
1352
- return SerializeFlowToCommandsResultFailure()
1352
+ return SerializeFlowToCommandsResultFailure(result_details=details)
1353
1353
 
1354
1354
  # Serialize each node
1355
1355
  for node_name in nodes_in_flow_result.node_names:
@@ -1357,7 +1357,7 @@ class FlowManager:
1357
1357
  if node is None:
1358
1358
  details = f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to serialize Node '{node_name}' within the Flow."
1359
1359
  logger.error(details)
1360
- return SerializeFlowToCommandsResultFailure()
1360
+ return SerializeFlowToCommandsResultFailure(result_details=details)
1361
1361
  with GriptapeNodes.ContextManager().node(node):
1362
1362
  # Note: the parameter value stuff is pass-by-reference, and we expect the values to be modified in place.
1363
1363
  # This might be dangerous if done over the wire.
@@ -1369,7 +1369,7 @@ class FlowManager:
1369
1369
  if not isinstance(serialize_node_result, SerializeNodeToCommandsResultSuccess):
1370
1370
  details = f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to serialize Node '{node_name}' within the Flow."
1371
1371
  logger.error(details)
1372
- return SerializeFlowToCommandsResultFailure()
1372
+ return SerializeFlowToCommandsResultFailure(result_details=details)
1373
1373
 
1374
1374
  serialized_node = serialize_node_result.serialized_node_commands
1375
1375
 
@@ -1409,7 +1409,7 @@ class FlowManager:
1409
1409
  if not isinstance(flows_in_flow_result, ListFlowsInFlowResultSuccess):
1410
1410
  details = f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to list child Flows in the Flow."
1411
1411
  logger.error(details)
1412
- return SerializeFlowToCommandsResultFailure()
1412
+ return SerializeFlowToCommandsResultFailure(result_details=details)
1413
1413
 
1414
1414
  sub_flow_commands = []
1415
1415
  for child_flow in flows_in_flow_result.flow_names:
@@ -1417,7 +1417,7 @@ class FlowManager:
1417
1417
  if flow is None:
1418
1418
  details = f"Attempted to serialize Flow '{flow_name}', but no Flow with that name could be found."
1419
1419
  logger.error(details)
1420
- return SerializeFlowToCommandsResultFailure()
1420
+ return SerializeFlowToCommandsResultFailure(result_details=details)
1421
1421
 
1422
1422
  # Check if this is a referenced workflow
1423
1423
  if self.is_referenced_workflow(flow):
@@ -1484,7 +1484,7 @@ class FlowManager:
1484
1484
  else:
1485
1485
  details = "Attempted to deserialize a set of Flow Creation commands into the Current Context. Failed because the Current Context was empty."
1486
1486
  logger.error(details)
1487
- return DeserializeFlowFromCommandsResultFailure()
1487
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1488
1488
  else:
1489
1489
  # Issue the creation command first.
1490
1490
  flow_initialization_command = request.serialized_flow_commands.flow_initialization_command
@@ -1496,25 +1496,25 @@ class FlowManager:
1496
1496
  if not isinstance(flow_initialization_result, CreateFlowResultSuccess):
1497
1497
  details = f"Attempted to deserialize a serialized set of Flow Creation commands. Failed to create flow '{flow_initialization_command.flow_name}'."
1498
1498
  logger.error(details)
1499
- return DeserializeFlowFromCommandsResultFailure()
1499
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1500
1500
  flow_name = flow_initialization_result.flow_name
1501
1501
  case ImportWorkflowAsReferencedSubFlowRequest():
1502
1502
  if not isinstance(flow_initialization_result, ImportWorkflowAsReferencedSubFlowResultSuccess):
1503
1503
  details = f"Attempted to deserialize a serialized set of Flow Creation commands. Failed to import workflow '{flow_initialization_command.workflow_name}'."
1504
1504
  logger.error(details)
1505
- return DeserializeFlowFromCommandsResultFailure()
1505
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1506
1506
  flow_name = flow_initialization_result.created_flow_name
1507
1507
  case _:
1508
1508
  details = f"Attempted to deserialize Flow Creation commands with unknown command type: {type(flow_initialization_command).__name__}."
1509
1509
  logger.error(details)
1510
- return DeserializeFlowFromCommandsResultFailure()
1510
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1511
1511
 
1512
1512
  # Adopt the newly-created flow as our current context.
1513
1513
  flow = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(flow_name, ControlFlow)
1514
1514
  if flow is None:
1515
1515
  details = f"Attempted to deserialize a serialized set of Flow Creation commands. Failed to find created flow '{flow_name}'."
1516
1516
  logger.error(details)
1517
- return DeserializeFlowFromCommandsResultFailure()
1517
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1518
1518
  GriptapeNodes.ContextManager().push_flow(flow=flow)
1519
1519
 
1520
1520
  # Deserializing a flow goes in a specific order.
@@ -1530,7 +1530,7 @@ class FlowManager:
1530
1530
  f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a node within the flow."
1531
1531
  )
1532
1532
  logger.error(details)
1533
- return DeserializeFlowFromCommandsResultFailure()
1533
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1534
1534
  node_uuid_to_deserialized_node_result[serialized_node.node_uuid] = deserialized_node_result
1535
1535
 
1536
1536
  # Now apply the connections.
@@ -1542,12 +1542,12 @@ class FlowManager:
1542
1542
  if source_node_uuid not in node_uuid_to_deserialized_node_result:
1543
1543
  details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while attempting to create a Connection for a source node that did not exist within the flow."
1544
1544
  logger.error(details)
1545
- return DeserializeFlowFromCommandsResultFailure()
1545
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1546
1546
  target_node_uuid = indirect_connection.target_node_uuid
1547
1547
  if target_node_uuid not in node_uuid_to_deserialized_node_result:
1548
1548
  details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while attempting to create a Connection for a target node that did not exist within the flow."
1549
1549
  logger.error(details)
1550
- return DeserializeFlowFromCommandsResultFailure()
1550
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1551
1551
 
1552
1552
  source_node_result = node_uuid_to_deserialized_node_result[source_node_uuid]
1553
1553
  source_node_name = source_node_result.node_name
@@ -1564,7 +1564,7 @@ class FlowManager:
1564
1564
  if create_connection_result.failed():
1565
1565
  details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a Connection from '{source_node_name}.{indirect_connection.source_parameter_name}' to '{target_node_name}.{indirect_connection.target_parameter_name}' within the flow."
1566
1566
  logger.error(details)
1567
- return DeserializeFlowFromCommandsResultFailure()
1567
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1568
1568
 
1569
1569
  # Now assign the values.
1570
1570
  # This is the same issue that we handle for Connections:
@@ -1578,7 +1578,7 @@ class FlowManager:
1578
1578
  if node is None:
1579
1579
  details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a value assignment for node '{node_name}'."
1580
1580
  logger.error(details)
1581
- return DeserializeFlowFromCommandsResultFailure()
1581
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1582
1582
  with GriptapeNodes.ContextManager().node(node=node):
1583
1583
  # Iterate through each set value command in the list for this node.
1584
1584
  for indirect_set_value_command in set_value_command_list:
@@ -1589,7 +1589,7 @@ class FlowManager:
1589
1589
  except IndexError as err:
1590
1590
  details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a value assignment for node '{node.name}.{parameter_name}': {err}"
1591
1591
  logger.error(details)
1592
- return DeserializeFlowFromCommandsResultFailure()
1592
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1593
1593
 
1594
1594
  # Call the SetParameterValueRequest, subbing in the value from our unique value list.
1595
1595
  indirect_set_value_command.set_parameter_value_command.value = value
@@ -1599,7 +1599,7 @@ class FlowManager:
1599
1599
  if set_parameter_value_result.failed():
1600
1600
  details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a value assignment for node '{node.name}.{parameter_name}'."
1601
1601
  logger.error(details)
1602
- return DeserializeFlowFromCommandsResultFailure()
1602
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1603
1603
 
1604
1604
  # Now the child flows.
1605
1605
  for sub_flow_command in request.serialized_flow_commands.sub_flows_commands:
@@ -1608,7 +1608,7 @@ class FlowManager:
1608
1608
  if sub_flow_result.failed():
1609
1609
  details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a sub-flow within the Flow."
1610
1610
  logger.error(details)
1611
- return DeserializeFlowFromCommandsResultFailure()
1611
+ return DeserializeFlowFromCommandsResultFailure(result_details=details)
1612
1612
 
1613
1613
  details = f"Successfully deserialized Flow '{flow_name}'."
1614
1614
  logger.debug(details)