griptape-nodes 0.52.1__py3-none-any.whl → 0.53.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/__init__.py +6 -943
- griptape_nodes/__main__.py +6 -0
- griptape_nodes/app/app.py +45 -61
- griptape_nodes/cli/__init__.py +1 -0
- griptape_nodes/cli/commands/__init__.py +1 -0
- griptape_nodes/cli/commands/config.py +71 -0
- griptape_nodes/cli/commands/engine.py +80 -0
- griptape_nodes/cli/commands/init.py +548 -0
- griptape_nodes/cli/commands/libraries.py +90 -0
- griptape_nodes/cli/commands/self.py +117 -0
- griptape_nodes/cli/main.py +46 -0
- griptape_nodes/cli/shared.py +84 -0
- griptape_nodes/common/__init__.py +1 -0
- griptape_nodes/common/directed_graph.py +55 -0
- griptape_nodes/drivers/storage/local_storage_driver.py +7 -2
- griptape_nodes/exe_types/core_types.py +60 -2
- griptape_nodes/exe_types/node_types.py +38 -24
- griptape_nodes/machines/control_flow.py +86 -22
- griptape_nodes/machines/fsm.py +10 -1
- griptape_nodes/machines/parallel_resolution.py +570 -0
- griptape_nodes/machines/{node_resolution.py → sequential_resolution.py} +22 -51
- griptape_nodes/retained_mode/events/base_events.py +2 -2
- griptape_nodes/retained_mode/events/node_events.py +4 -3
- griptape_nodes/retained_mode/griptape_nodes.py +25 -12
- griptape_nodes/retained_mode/managers/agent_manager.py +9 -5
- griptape_nodes/retained_mode/managers/arbitrary_code_exec_manager.py +3 -1
- griptape_nodes/retained_mode/managers/context_manager.py +6 -5
- griptape_nodes/retained_mode/managers/flow_manager.py +117 -204
- griptape_nodes/retained_mode/managers/library_lifecycle/library_directory.py +1 -1
- griptape_nodes/retained_mode/managers/library_manager.py +35 -25
- griptape_nodes/retained_mode/managers/node_manager.py +81 -199
- griptape_nodes/retained_mode/managers/object_manager.py +11 -5
- griptape_nodes/retained_mode/managers/os_manager.py +24 -9
- griptape_nodes/retained_mode/managers/secrets_manager.py +8 -4
- griptape_nodes/retained_mode/managers/settings.py +32 -1
- griptape_nodes/retained_mode/managers/static_files_manager.py +8 -3
- griptape_nodes/retained_mode/managers/sync_manager.py +8 -5
- griptape_nodes/retained_mode/managers/workflow_manager.py +110 -122
- griptape_nodes/traits/add_param_button.py +1 -1
- griptape_nodes/traits/button.py +216 -6
- griptape_nodes/traits/color_picker.py +66 -0
- griptape_nodes/traits/traits.json +4 -0
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.53.0.dist-info}/METADATA +2 -1
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.53.0.dist-info}/RECORD +46 -32
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.53.0.dist-info}/WHEEL +0 -0
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.53.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
+
from enum import StrEnum
|
|
4
5
|
from queue import Queue
|
|
5
|
-
from typing import TYPE_CHECKING, cast
|
|
6
|
+
from typing import TYPE_CHECKING, NamedTuple, cast
|
|
6
7
|
|
|
7
8
|
from griptape_nodes.exe_types.connections import Connections
|
|
8
9
|
from griptape_nodes.exe_types.core_types import (
|
|
@@ -20,6 +21,7 @@ from griptape_nodes.retained_mode.events.base_events import (
|
|
|
20
21
|
ExecutionGriptapeNodeEvent,
|
|
21
22
|
FlushParameterChangesRequest,
|
|
22
23
|
FlushParameterChangesResultSuccess,
|
|
24
|
+
ResultDetails,
|
|
23
25
|
)
|
|
24
26
|
from griptape_nodes.retained_mode.events.connection_events import (
|
|
25
27
|
CreateConnectionRequest,
|
|
@@ -120,13 +122,26 @@ if TYPE_CHECKING:
|
|
|
120
122
|
logger = logging.getLogger("griptape_nodes")
|
|
121
123
|
|
|
122
124
|
|
|
125
|
+
class DagExecutionType(StrEnum):
|
|
126
|
+
START_NODE = "start_node"
|
|
127
|
+
CONTROL_NODE = "control_node"
|
|
128
|
+
DATA_NODE = "data_node"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class QueueItem(NamedTuple):
|
|
132
|
+
"""Represents an item in the flow execution queue."""
|
|
133
|
+
|
|
134
|
+
node: BaseNode
|
|
135
|
+
dag_execution_type: DagExecutionType
|
|
136
|
+
|
|
137
|
+
|
|
123
138
|
class FlowManager:
|
|
124
139
|
_name_to_parent_name: dict[str, str | None]
|
|
125
140
|
_flow_to_referenced_workflow_name: dict[ControlFlow, str]
|
|
126
141
|
_connections: Connections
|
|
127
142
|
|
|
128
143
|
# Global execution state (moved from individual ControlFlows)
|
|
129
|
-
_global_flow_queue: Queue[
|
|
144
|
+
_global_flow_queue: Queue[QueueItem]
|
|
130
145
|
_global_control_flow_machine: ControlFlowMachine | None
|
|
131
146
|
_global_single_node_resolution: bool
|
|
132
147
|
|
|
@@ -169,10 +184,14 @@ class FlowManager:
|
|
|
169
184
|
self._connections = Connections()
|
|
170
185
|
|
|
171
186
|
# Initialize global execution state
|
|
172
|
-
self._global_flow_queue = Queue[
|
|
173
|
-
self._global_control_flow_machine = None #
|
|
187
|
+
self._global_flow_queue = Queue[QueueItem]()
|
|
188
|
+
self._global_control_flow_machine = None # Track the current control flow machine
|
|
174
189
|
self._global_single_node_resolution = False
|
|
175
190
|
|
|
191
|
+
@property
|
|
192
|
+
def global_flow_queue(self) -> Queue[QueueItem]:
|
|
193
|
+
return self._global_flow_queue
|
|
194
|
+
|
|
176
195
|
def get_connections(self) -> Connections:
|
|
177
196
|
"""Get the connections instance."""
|
|
178
197
|
return self._connections
|
|
@@ -238,10 +257,12 @@ class FlowManager:
|
|
|
238
257
|
def on_get_top_level_flow_request(self, request: GetTopLevelFlowRequest) -> ResultPayload: # noqa: ARG002 (the request has to be assigned to the method)
|
|
239
258
|
for flow_name, parent in self._name_to_parent_name.items():
|
|
240
259
|
if parent is None:
|
|
241
|
-
return GetTopLevelFlowResultSuccess(
|
|
260
|
+
return GetTopLevelFlowResultSuccess(
|
|
261
|
+
flow_name=flow_name, result_details=f"Successfully found top level flow: '{flow_name}'"
|
|
262
|
+
)
|
|
242
263
|
msg = "Attempted to get top level flow, but no such flow exists"
|
|
243
264
|
logger.debug(msg)
|
|
244
|
-
return GetTopLevelFlowResultSuccess(flow_name=None)
|
|
265
|
+
return GetTopLevelFlowResultSuccess(flow_name=None, result_details=msg)
|
|
245
266
|
|
|
246
267
|
def on_get_flow_details_request(self, request: GetFlowDetailsRequest) -> ResultPayload:
|
|
247
268
|
flow_name = request.flow_name
|
|
@@ -251,7 +272,6 @@ class FlowManager:
|
|
|
251
272
|
# We want to get details for whatever is at the top of the Current Context.
|
|
252
273
|
if not GriptapeNodes.ContextManager().has_current_flow():
|
|
253
274
|
details = "Attempted to get Flow details from the Current Context. Failed because the Current Context was empty."
|
|
254
|
-
logger.error(details)
|
|
255
275
|
return GetFlowDetailsResultFailure(result_details=details)
|
|
256
276
|
flow = GriptapeNodes.ContextManager().get_current_flow()
|
|
257
277
|
flow_name = flow.name
|
|
@@ -261,14 +281,12 @@ class FlowManager:
|
|
|
261
281
|
details = (
|
|
262
282
|
f"Attempted to get Flow details for '{flow_name}'. Failed because no Flow with that name exists."
|
|
263
283
|
)
|
|
264
|
-
logger.error(details)
|
|
265
284
|
return GetFlowDetailsResultFailure(result_details=details)
|
|
266
285
|
|
|
267
286
|
try:
|
|
268
287
|
parent_flow_name = self.get_parent_flow(flow_name)
|
|
269
288
|
except ValueError:
|
|
270
289
|
details = f"Attempted to get Flow details for '{flow_name}'. Failed because Flow does not exist in parent mapping."
|
|
271
|
-
logger.error(details)
|
|
272
290
|
return GetFlowDetailsResultFailure(result_details=details)
|
|
273
291
|
|
|
274
292
|
referenced_workflow_name = None
|
|
@@ -276,10 +294,8 @@ class FlowManager:
|
|
|
276
294
|
referenced_workflow_name = self.get_referenced_workflow_name(flow)
|
|
277
295
|
|
|
278
296
|
details = f"Successfully retrieved Flow details for '{flow_name}'."
|
|
279
|
-
logger.debug(details)
|
|
280
297
|
return GetFlowDetailsResultSuccess(
|
|
281
|
-
referenced_workflow_name=referenced_workflow_name,
|
|
282
|
-
parent_flow_name=parent_flow_name,
|
|
298
|
+
referenced_workflow_name=referenced_workflow_name, parent_flow_name=parent_flow_name, result_details=details
|
|
283
299
|
)
|
|
284
300
|
|
|
285
301
|
def on_get_flow_metadata_request(self, request: GetFlowMetadataRequest) -> ResultPayload:
|
|
@@ -289,7 +305,6 @@ class FlowManager:
|
|
|
289
305
|
# Get from the current context.
|
|
290
306
|
if not GriptapeNodes.ContextManager().has_current_flow():
|
|
291
307
|
details = "Attempted to get metadata for a Flow from the Current Context. Failed because the Current Context is empty."
|
|
292
|
-
logger.error(details)
|
|
293
308
|
return GetFlowMetadataResultFailure(result_details=details)
|
|
294
309
|
|
|
295
310
|
flow = GriptapeNodes.ContextManager().get_current_flow()
|
|
@@ -301,14 +316,12 @@ class FlowManager:
|
|
|
301
316
|
flow = obj_mgr.attempt_get_object_by_name_as_type(flow_name, ControlFlow)
|
|
302
317
|
if flow is None:
|
|
303
318
|
details = f"Attempted to get metadata for a Flow '{flow_name}', but no such Flow was found."
|
|
304
|
-
logger.error(details)
|
|
305
319
|
return GetFlowMetadataResultFailure(result_details=details)
|
|
306
320
|
|
|
307
321
|
metadata = flow.metadata
|
|
308
322
|
details = f"Successfully retrieved metadata for a Flow '{flow_name}'."
|
|
309
|
-
logger.debug(details)
|
|
310
323
|
|
|
311
|
-
return GetFlowMetadataResultSuccess(metadata=metadata)
|
|
324
|
+
return GetFlowMetadataResultSuccess(metadata=metadata, result_details=details)
|
|
312
325
|
|
|
313
326
|
def on_set_flow_metadata_request(self, request: SetFlowMetadataRequest) -> ResultPayload:
|
|
314
327
|
flow_name = request.flow_name
|
|
@@ -317,7 +330,6 @@ class FlowManager:
|
|
|
317
330
|
# Get from the current context.
|
|
318
331
|
if not GriptapeNodes.ContextManager().has_current_flow():
|
|
319
332
|
details = "Attempted to set metadata for a Flow from the Current Context. Failed because the Current Context is empty."
|
|
320
|
-
logger.error(details)
|
|
321
333
|
return SetFlowMetadataResultFailure(result_details=details)
|
|
322
334
|
|
|
323
335
|
flow = GriptapeNodes.ContextManager().get_current_flow()
|
|
@@ -329,16 +341,14 @@ class FlowManager:
|
|
|
329
341
|
flow = obj_mgr.attempt_get_object_by_name_as_type(flow_name, ControlFlow)
|
|
330
342
|
if flow is None:
|
|
331
343
|
details = f"Attempted to set metadata for a Flow '{flow_name}', but no such Flow was found."
|
|
332
|
-
logger.error(details)
|
|
333
344
|
return SetFlowMetadataResultFailure(result_details=details)
|
|
334
345
|
|
|
335
346
|
# We can't completely overwrite metadata.
|
|
336
347
|
for key, value in request.metadata.items():
|
|
337
348
|
flow.metadata[key] = value
|
|
338
349
|
details = f"Successfully set metadata for a Flow '{flow_name}'."
|
|
339
|
-
logger.debug(details)
|
|
340
350
|
|
|
341
|
-
return SetFlowMetadataResultSuccess()
|
|
351
|
+
return SetFlowMetadataResultSuccess(result_details=details)
|
|
342
352
|
|
|
343
353
|
def does_canvas_exist(self) -> bool:
|
|
344
354
|
"""Determines if there is already an existing flow with no parent flow.Returns True if there is an existing flow with no parent flow.Return False if there is no existing flow with no parent flow."""
|
|
@@ -368,13 +378,11 @@ class FlowManager:
|
|
|
368
378
|
if self.does_canvas_exist():
|
|
369
379
|
# We're trying to create the canvas. Ensure that parent does NOT already exist.
|
|
370
380
|
details = "Attempted to create a Flow as the Canvas (top-level Flow with no parents), but the Canvas already exists."
|
|
371
|
-
logger.error(details)
|
|
372
381
|
result = CreateFlowResultFailure(result_details=details)
|
|
373
382
|
return result
|
|
374
383
|
# Now our parent exists, right?
|
|
375
384
|
elif parent is None:
|
|
376
385
|
details = f"Attempted to create a Flow with a parent '{request.parent_flow_name}', but no parent with that name could be found."
|
|
377
|
-
logger.error(details)
|
|
378
386
|
|
|
379
387
|
result = CreateFlowResultFailure(result_details=details)
|
|
380
388
|
|
|
@@ -383,7 +391,6 @@ class FlowManager:
|
|
|
383
391
|
# We need to have a current workflow context to proceed.
|
|
384
392
|
if not GriptapeNodes.ContextManager().has_current_workflow():
|
|
385
393
|
details = "Attempted to create a Flow, but no Workflow was active in the Current Context."
|
|
386
|
-
logger.error(details)
|
|
387
394
|
return CreateFlowResultFailure(result_details=details)
|
|
388
395
|
|
|
389
396
|
# Create it.
|
|
@@ -409,13 +416,14 @@ class FlowManager:
|
|
|
409
416
|
|
|
410
417
|
# Success
|
|
411
418
|
details = f"Successfully created Flow '{final_flow_name}'."
|
|
412
|
-
log_level =
|
|
419
|
+
log_level = "DEBUG"
|
|
413
420
|
if (request.flow_name is not None) and (final_flow_name != request.flow_name):
|
|
414
421
|
details = f"{details} WARNING: Had to rename from original Flow requested '{request.flow_name}' as an object with this name already existed."
|
|
415
|
-
log_level =
|
|
422
|
+
log_level = "WARNING"
|
|
416
423
|
|
|
417
|
-
|
|
418
|
-
|
|
424
|
+
result = CreateFlowResultSuccess(
|
|
425
|
+
flow_name=final_flow_name, result_details=ResultDetails(message=details, level=log_level)
|
|
426
|
+
)
|
|
419
427
|
return result
|
|
420
428
|
|
|
421
429
|
# This needs to have a lot of branches to check the flow in all possible situations. In Current Context, or when the name is passed in.
|
|
@@ -428,7 +436,6 @@ class FlowManager:
|
|
|
428
436
|
details = (
|
|
429
437
|
"Attempted to delete a Flow from the Current Context. Failed because the Current Context was empty."
|
|
430
438
|
)
|
|
431
|
-
logger.error(details)
|
|
432
439
|
result = DeleteFlowResultFailure(result_details=details)
|
|
433
440
|
return result
|
|
434
441
|
# We pop it off here, but we'll re-add it using context in a moment.
|
|
@@ -440,14 +447,12 @@ class FlowManager:
|
|
|
440
447
|
flow = obj_mgr.attempt_get_object_by_name_as_type(flow_name, ControlFlow)
|
|
441
448
|
if flow is None:
|
|
442
449
|
details = f"Attempted to delete Flow '{flow_name}', but no Flow with that name could be found."
|
|
443
|
-
logger.error(details)
|
|
444
450
|
result = DeleteFlowResultFailure(result_details=details)
|
|
445
451
|
return result
|
|
446
452
|
if self.check_for_existing_running_flow():
|
|
447
453
|
result = GriptapeNodes.handle_request(CancelFlowRequest(flow_name=flow.name))
|
|
448
454
|
if not result.succeeded():
|
|
449
455
|
details = f"Attempted to delete flow '{flow_name}'. Failed because running flow could not cancel."
|
|
450
|
-
logger.error(details)
|
|
451
456
|
return DeleteFlowResultFailure(result_details=details)
|
|
452
457
|
|
|
453
458
|
# Let this Flow assume the Current Context while we delete everything within it.
|
|
@@ -457,7 +462,6 @@ class FlowManager:
|
|
|
457
462
|
list_nodes_result = GriptapeNodes.handle_request(list_nodes_request)
|
|
458
463
|
if not isinstance(list_nodes_result, ListNodesInFlowResultSuccess):
|
|
459
464
|
details = f"Attempted to delete Flow '{flow.name}', but failed while attempting to get the list of Nodes owned by this Flow."
|
|
460
|
-
logger.error(details)
|
|
461
465
|
result = DeleteFlowResultFailure(result_details=details)
|
|
462
466
|
return result
|
|
463
467
|
node_names = list_nodes_result.node_names
|
|
@@ -466,7 +470,6 @@ class FlowManager:
|
|
|
466
470
|
delete_node_result = GriptapeNodes.handle_request(delete_node_request)
|
|
467
471
|
if isinstance(delete_node_result, DeleteNodeResultFailure):
|
|
468
472
|
details = f"Attempted to delete Flow '{flow.name}', but failed while attempting to delete child Node '{node_name}'."
|
|
469
|
-
logger.error(details)
|
|
470
473
|
result = DeleteFlowResultFailure(result_details=details)
|
|
471
474
|
return result
|
|
472
475
|
|
|
@@ -478,7 +481,6 @@ class FlowManager:
|
|
|
478
481
|
list_flows_result = GriptapeNodes.handle_request(list_flows_request)
|
|
479
482
|
if not isinstance(list_flows_result, ListFlowsInCurrentContextResultSuccess):
|
|
480
483
|
details = f"Attempted to delete Flow '{flow_name}', but failed while attempting to get the list of Flows owned by this Flow."
|
|
481
|
-
logger.error(details)
|
|
482
484
|
result = DeleteFlowResultFailure(result_details=details)
|
|
483
485
|
return result
|
|
484
486
|
flow_names = list_flows_result.flow_names
|
|
@@ -489,7 +491,6 @@ class FlowManager:
|
|
|
489
491
|
details = (
|
|
490
492
|
f"Attempted to delete Flow '{child_flow_name}', but no Flow with that name could be found."
|
|
491
493
|
)
|
|
492
|
-
logger.error(details)
|
|
493
494
|
result = DeleteFlowResultFailure(result_details=details)
|
|
494
495
|
return result
|
|
495
496
|
with GriptapeNodes.ContextManager().flow(flow=child_flow):
|
|
@@ -498,7 +499,6 @@ class FlowManager:
|
|
|
498
499
|
delete_flow_result = GriptapeNodes.handle_request(delete_flow_request)
|
|
499
500
|
if isinstance(delete_flow_result, DeleteFlowResultFailure):
|
|
500
501
|
details = f"Attempted to delete Flow '{flow.name}', but failed while attempting to delete child Flow '{child_flow.name}'."
|
|
501
|
-
logger.error(details)
|
|
502
502
|
result = DeleteFlowResultFailure(result_details=details)
|
|
503
503
|
return result
|
|
504
504
|
|
|
@@ -511,31 +511,32 @@ class FlowManager:
|
|
|
511
511
|
if flow in self._flow_to_referenced_workflow_name:
|
|
512
512
|
del self._flow_to_referenced_workflow_name[flow]
|
|
513
513
|
|
|
514
|
+
# Clean up ControlFlowMachine and DAG orchestrator for this flow
|
|
515
|
+
self._global_control_flow_machine = None
|
|
516
|
+
|
|
514
517
|
details = f"Successfully deleted Flow '{flow_name}'."
|
|
515
|
-
|
|
516
|
-
result = DeleteFlowResultSuccess()
|
|
518
|
+
result = DeleteFlowResultSuccess(result_details=details)
|
|
517
519
|
return result
|
|
518
520
|
|
|
519
521
|
def on_get_is_flow_running_request(self, request: GetIsFlowRunningRequest) -> ResultPayload:
|
|
520
522
|
obj_mgr = GriptapeNodes.ObjectManager()
|
|
521
523
|
if request.flow_name is None:
|
|
522
524
|
details = "Attempted to get Flow, but no flow name was provided."
|
|
523
|
-
logger.error(details)
|
|
524
525
|
return GetIsFlowRunningResultFailure(result_details=details)
|
|
525
526
|
flow = obj_mgr.attempt_get_object_by_name_as_type(request.flow_name, ControlFlow)
|
|
526
527
|
if flow is None:
|
|
527
528
|
details = f"Attempted to get Flow '{request.flow_name}', but no Flow with that name could be found."
|
|
528
|
-
logger.error(details)
|
|
529
529
|
result = GetIsFlowRunningResultFailure(result_details=details)
|
|
530
530
|
return result
|
|
531
531
|
try:
|
|
532
532
|
is_running = self.check_for_existing_running_flow()
|
|
533
533
|
except Exception:
|
|
534
534
|
details = f"Error while trying to get status of '{request.flow_name}'."
|
|
535
|
-
logger.error(details)
|
|
536
535
|
result = GetIsFlowRunningResultFailure(result_details=details)
|
|
537
536
|
return result
|
|
538
|
-
return GetIsFlowRunningResultSuccess(
|
|
537
|
+
return GetIsFlowRunningResultSuccess(
|
|
538
|
+
is_running=is_running, result_details=f"Successfully checked if flow is running: {is_running}"
|
|
539
|
+
)
|
|
539
540
|
|
|
540
541
|
def on_list_nodes_in_flow_request(self, request: ListNodesInFlowRequest) -> ResultPayload:
|
|
541
542
|
flow_name = request.flow_name
|
|
@@ -544,7 +545,6 @@ class FlowManager:
|
|
|
544
545
|
# First check if we have a current flow
|
|
545
546
|
if not GriptapeNodes.ContextManager().has_current_flow():
|
|
546
547
|
details = "Attempted to list Nodes in a Flow in the Current Context. Failed because the Current Context was empty."
|
|
547
|
-
logger.error(details)
|
|
548
548
|
result = ListNodesInFlowResultFailure(result_details=details)
|
|
549
549
|
return result
|
|
550
550
|
# Get the current flow from context
|
|
@@ -558,15 +558,13 @@ class FlowManager:
|
|
|
558
558
|
details = (
|
|
559
559
|
f"Attempted to list Nodes in Flow '{flow_name}'. Failed because no Flow with that name could be found."
|
|
560
560
|
)
|
|
561
|
-
logger.error(details)
|
|
562
561
|
result = ListNodesInFlowResultFailure(result_details=details)
|
|
563
562
|
return result
|
|
564
563
|
|
|
565
564
|
ret_list = list(flow.nodes.keys())
|
|
566
565
|
details = f"Successfully got the list of Nodes within Flow '{flow_name}'."
|
|
567
|
-
logger.debug(details)
|
|
568
566
|
|
|
569
|
-
result = ListNodesInFlowResultSuccess(node_names=ret_list)
|
|
567
|
+
result = ListNodesInFlowResultSuccess(node_names=ret_list, result_details=details)
|
|
570
568
|
return result
|
|
571
569
|
|
|
572
570
|
def on_list_flows_in_flow_request(self, request: ListFlowsInFlowRequest) -> ResultPayload:
|
|
@@ -576,7 +574,6 @@ class FlowManager:
|
|
|
576
574
|
flow = obj_mgr.attempt_get_object_by_name_as_type(request.parent_flow_name, ControlFlow)
|
|
577
575
|
if flow is None:
|
|
578
576
|
details = f"Attempted to list Flows that are children of Flow '{request.parent_flow_name}', but no Flow with that name could be found."
|
|
579
|
-
logger.error(details)
|
|
580
577
|
result = ListFlowsInFlowResultFailure(result_details=details)
|
|
581
578
|
return result
|
|
582
579
|
|
|
@@ -587,9 +584,8 @@ class FlowManager:
|
|
|
587
584
|
ret_list.append(flow_name)
|
|
588
585
|
|
|
589
586
|
details = f"Successfully got the list of Flows that are direct children of Flow '{request.parent_flow_name}'."
|
|
590
|
-
logger.debug(details)
|
|
591
587
|
|
|
592
|
-
result = ListFlowsInFlowResultSuccess(flow_names=ret_list)
|
|
588
|
+
result = ListFlowsInFlowResultSuccess(flow_names=ret_list, result_details=details)
|
|
593
589
|
return result
|
|
594
590
|
|
|
595
591
|
def get_flow_by_name(self, flow_name: str) -> ControlFlow:
|
|
@@ -623,7 +619,6 @@ class FlowManager:
|
|
|
623
619
|
# First check if we have a current node
|
|
624
620
|
if not GriptapeNodes.ContextManager().has_current_node():
|
|
625
621
|
details = "Attempted to create a Connection with a source node from the Current Context. Failed because the Current Context was empty."
|
|
626
|
-
logger.error(details)
|
|
627
622
|
return CreateConnectionResultFailure(result_details=details)
|
|
628
623
|
|
|
629
624
|
# Get the current node from context
|
|
@@ -634,7 +629,6 @@ class FlowManager:
|
|
|
634
629
|
source_node = GriptapeNodes.NodeManager().get_node_by_name(source_node_name)
|
|
635
630
|
except ValueError as err:
|
|
636
631
|
details = f'Connection failed: "{source_node_name}" does not exist. Error: {err}.'
|
|
637
|
-
logger.error(details)
|
|
638
632
|
|
|
639
633
|
return CreateConnectionResultFailure(result_details=details)
|
|
640
634
|
|
|
@@ -644,7 +638,6 @@ class FlowManager:
|
|
|
644
638
|
# First check if we have a current node
|
|
645
639
|
if not GriptapeNodes.ContextManager().has_current_node():
|
|
646
640
|
details = "Attempted to create a Connection with the target node from the Current Context. Failed because the Current Context was empty."
|
|
647
|
-
logger.error(details)
|
|
648
641
|
return CreateConnectionResultFailure(result_details=details)
|
|
649
642
|
|
|
650
643
|
# Get the current node from context
|
|
@@ -655,7 +648,6 @@ class FlowManager:
|
|
|
655
648
|
target_node = GriptapeNodes.NodeManager().get_node_by_name(target_node_name)
|
|
656
649
|
except ValueError as err:
|
|
657
650
|
details = f'Connection failed: "{target_node_name}" does not exist. Error: {err}.'
|
|
658
|
-
logger.error(details)
|
|
659
651
|
return CreateConnectionResultFailure(result_details=details)
|
|
660
652
|
|
|
661
653
|
# The two nodes exist.
|
|
@@ -666,7 +658,6 @@ class FlowManager:
|
|
|
666
658
|
self.get_flow_by_name(flow_name=source_flow_name)
|
|
667
659
|
except KeyError as err:
|
|
668
660
|
details = f'Connection "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}" failed: {err}.'
|
|
669
|
-
logger.error(details)
|
|
670
661
|
return CreateConnectionResultFailure(result_details=details)
|
|
671
662
|
|
|
672
663
|
target_flow_name = None
|
|
@@ -675,7 +666,6 @@ class FlowManager:
|
|
|
675
666
|
self.get_flow_by_name(flow_name=target_flow_name)
|
|
676
667
|
except KeyError as err:
|
|
677
668
|
details = f'Connection "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}" failed: {err}.'
|
|
678
|
-
logger.error(details)
|
|
679
669
|
return CreateConnectionResultFailure(result_details=details)
|
|
680
670
|
|
|
681
671
|
# Cross-flow connections are now supported via global connection storage
|
|
@@ -696,14 +686,12 @@ class FlowManager:
|
|
|
696
686
|
source_param = source_node.get_parameter_by_name(request.source_parameter_name)
|
|
697
687
|
if source_param is None:
|
|
698
688
|
details = f'Connection failed: "{source_node_name}.{request.source_parameter_name}" not found'
|
|
699
|
-
logger.error(details)
|
|
700
689
|
return CreateConnectionResultFailure(result_details=details)
|
|
701
690
|
|
|
702
691
|
target_param = target_node.get_parameter_by_name(request.target_parameter_name)
|
|
703
692
|
if target_param is None:
|
|
704
693
|
# TODO: https://github.com/griptape-ai/griptape-nodes/issues/860
|
|
705
694
|
details = f'Connection failed: "{target_node_name}.{request.target_parameter_name}" not found'
|
|
706
|
-
logger.error(details)
|
|
707
695
|
return CreateConnectionResultFailure(result_details=details)
|
|
708
696
|
# Validate parameter modes accept this type of connection.
|
|
709
697
|
source_modes_allowed = source_param.allowed_modes
|
|
@@ -711,19 +699,16 @@ class FlowManager:
|
|
|
711
699
|
details = (
|
|
712
700
|
f'Connection failed: "{source_node_name}.{request.source_parameter_name}" is not an allowed OUTPUT'
|
|
713
701
|
)
|
|
714
|
-
logger.error(details)
|
|
715
702
|
return CreateConnectionResultFailure(result_details=details)
|
|
716
703
|
|
|
717
704
|
target_modes_allowed = target_param.allowed_modes
|
|
718
705
|
if ParameterMode.INPUT not in target_modes_allowed:
|
|
719
706
|
details = f'Connection failed: "{target_node_name}.{request.target_parameter_name}" is not an allowed INPUT'
|
|
720
|
-
logger.error(details)
|
|
721
707
|
return CreateConnectionResultFailure(result_details=details)
|
|
722
708
|
|
|
723
709
|
# Validate that the data type from the source is allowed by the target.
|
|
724
710
|
if not target_param.is_incoming_type_allowed(source_param.output_type):
|
|
725
711
|
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}) '
|
|
726
|
-
logger.error(details)
|
|
727
712
|
return CreateConnectionResultFailure(result_details=details)
|
|
728
713
|
|
|
729
714
|
# Ask each node involved to bless this union.
|
|
@@ -735,7 +720,6 @@ class FlowManager:
|
|
|
735
720
|
details = (
|
|
736
721
|
f'Connection failed : "{source_node_name}.{request.source_parameter_name}" rejected the connection '
|
|
737
722
|
)
|
|
738
|
-
logger.error(details)
|
|
739
723
|
return CreateConnectionResultFailure(result_details=details)
|
|
740
724
|
|
|
741
725
|
if not target_node.allow_incoming_connection(
|
|
@@ -746,7 +730,6 @@ class FlowManager:
|
|
|
746
730
|
details = (
|
|
747
731
|
f'Connection failed : "{target_node_name}.{request.target_parameter_name}" rejected the connection '
|
|
748
732
|
)
|
|
749
|
-
logger.error(details)
|
|
750
733
|
return CreateConnectionResultFailure(result_details=details)
|
|
751
734
|
|
|
752
735
|
# Based on user feedback, if a connection already exists in a scenario where only ONE such connection can exist
|
|
@@ -786,11 +769,9 @@ class FlowManager:
|
|
|
786
769
|
delete_old_result = GriptapeNodes.handle_request(delete_old_request)
|
|
787
770
|
if delete_old_result.failed():
|
|
788
771
|
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."
|
|
789
|
-
logger.error(details)
|
|
790
772
|
return CreateConnectionResultFailure(result_details=details)
|
|
791
773
|
|
|
792
774
|
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."
|
|
793
|
-
logger.debug(details)
|
|
794
775
|
try:
|
|
795
776
|
# Actually create the Connection.
|
|
796
777
|
self._connections.add_connection(
|
|
@@ -801,7 +782,6 @@ class FlowManager:
|
|
|
801
782
|
)
|
|
802
783
|
except ValueError as e:
|
|
803
784
|
details = f'Connection failed: "{e}"'
|
|
804
|
-
logger.error(details)
|
|
805
785
|
|
|
806
786
|
# Attempt to restore any old connection that may have been present.
|
|
807
787
|
if (
|
|
@@ -820,7 +800,6 @@ class FlowManager:
|
|
|
820
800
|
create_old_connection_result = GriptapeNodes.handle_request(create_old_connection_request)
|
|
821
801
|
if create_old_connection_result.failed():
|
|
822
802
|
details = "Failed attempting to restore the old Connection after failing the replacement. A thousand pardons."
|
|
823
|
-
logger.error(details)
|
|
824
803
|
return CreateConnectionResultFailure(result_details=details)
|
|
825
804
|
|
|
826
805
|
# Let the source make any internal handling decisions now that the Connection has been made.
|
|
@@ -836,7 +815,6 @@ class FlowManager:
|
|
|
836
815
|
)
|
|
837
816
|
|
|
838
817
|
details = f'Connected "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}"'
|
|
839
|
-
logger.debug(details)
|
|
840
818
|
|
|
841
819
|
# Now update the parameter values if it exists.
|
|
842
820
|
# check if it's been resolved/has a value in parameter_output_values
|
|
@@ -879,7 +857,7 @@ class FlowManager:
|
|
|
879
857
|
if isinstance(target_node, ErrorProxyNode):
|
|
880
858
|
target_node.set_post_init_connections_modified()
|
|
881
859
|
|
|
882
|
-
result = CreateConnectionResultSuccess()
|
|
860
|
+
result = CreateConnectionResultSuccess(result_details=details)
|
|
883
861
|
|
|
884
862
|
return result
|
|
885
863
|
|
|
@@ -893,7 +871,6 @@ class FlowManager:
|
|
|
893
871
|
# First check if we have a current node
|
|
894
872
|
if not GriptapeNodes.ContextManager().has_current_node():
|
|
895
873
|
details = "Attempted to delete a Connection with a source node from the Current Context. Failed because the Current Context was empty."
|
|
896
|
-
logger.error(details)
|
|
897
874
|
return DeleteConnectionResultFailure(result_details=details)
|
|
898
875
|
|
|
899
876
|
# Get the current node from context
|
|
@@ -904,7 +881,6 @@ class FlowManager:
|
|
|
904
881
|
source_node = GriptapeNodes.NodeManager().get_node_by_name(source_node_name)
|
|
905
882
|
except ValueError as err:
|
|
906
883
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
|
|
907
|
-
logger.error(details)
|
|
908
884
|
|
|
909
885
|
return DeleteConnectionResultFailure(result_details=details)
|
|
910
886
|
|
|
@@ -913,7 +889,6 @@ class FlowManager:
|
|
|
913
889
|
# First check if we have a current node
|
|
914
890
|
if not GriptapeNodes.ContextManager().has_current_node():
|
|
915
891
|
details = "Attempted to delete a Connection with a target node from the Current Context. Failed because the Current Context was empty."
|
|
916
|
-
logger.error(details)
|
|
917
892
|
return DeleteConnectionResultFailure(result_details=details)
|
|
918
893
|
|
|
919
894
|
# Get the current node from context
|
|
@@ -924,7 +899,6 @@ class FlowManager:
|
|
|
924
899
|
target_node = GriptapeNodes.NodeManager().get_node_by_name(target_node_name)
|
|
925
900
|
except ValueError as err:
|
|
926
901
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
|
|
927
|
-
logger.error(details)
|
|
928
902
|
|
|
929
903
|
return DeleteConnectionResultFailure(result_details=details)
|
|
930
904
|
|
|
@@ -936,7 +910,6 @@ class FlowManager:
|
|
|
936
910
|
self.get_flow_by_name(flow_name=source_flow_name)
|
|
937
911
|
except KeyError as err:
|
|
938
912
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
|
|
939
|
-
logger.error(details)
|
|
940
913
|
|
|
941
914
|
return DeleteConnectionResultFailure(result_details=details)
|
|
942
915
|
|
|
@@ -946,7 +919,6 @@ class FlowManager:
|
|
|
946
919
|
self.get_flow_by_name(flow_name=target_flow_name)
|
|
947
920
|
except KeyError as err:
|
|
948
921
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Error: {err}'
|
|
949
|
-
logger.error(details)
|
|
950
922
|
|
|
951
923
|
return DeleteConnectionResultFailure(result_details=details)
|
|
952
924
|
|
|
@@ -956,14 +928,12 @@ class FlowManager:
|
|
|
956
928
|
source_param = source_node.get_parameter_by_name(request.source_parameter_name)
|
|
957
929
|
if source_param is None:
|
|
958
930
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" Not found.'
|
|
959
|
-
logger.error(details)
|
|
960
931
|
|
|
961
932
|
return DeleteConnectionResultFailure(result_details=details)
|
|
962
933
|
|
|
963
934
|
target_param = target_node.get_parameter_by_name(request.target_parameter_name)
|
|
964
935
|
if target_param is None:
|
|
965
936
|
details = f'Connection not deleted "{target_node_name}.{request.target_parameter_name}" Not found.'
|
|
966
|
-
logger.error(details)
|
|
967
937
|
|
|
968
938
|
return DeleteConnectionResultFailure(result_details=details)
|
|
969
939
|
|
|
@@ -975,7 +945,6 @@ class FlowManager:
|
|
|
975
945
|
target_parameter=target_param,
|
|
976
946
|
):
|
|
977
947
|
details = f'Connection does not exist: "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}"'
|
|
978
|
-
logger.error(details)
|
|
979
948
|
|
|
980
949
|
return DeleteConnectionResultFailure(result_details=details)
|
|
981
950
|
|
|
@@ -987,7 +956,6 @@ class FlowManager:
|
|
|
987
956
|
target_parameter=target_param.name,
|
|
988
957
|
):
|
|
989
958
|
details = f'Connection not deleted "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}". Unknown failure.'
|
|
990
|
-
logger.error(details)
|
|
991
959
|
|
|
992
960
|
return DeleteConnectionResultFailure(result_details=details)
|
|
993
961
|
|
|
@@ -1020,7 +988,6 @@ class FlowManager:
|
|
|
1020
988
|
)
|
|
1021
989
|
|
|
1022
990
|
details = f'Connection "{source_node_name}.{request.source_parameter_name}" to "{target_node_name}.{request.target_parameter_name}" deleted.'
|
|
1023
|
-
logger.debug(details)
|
|
1024
991
|
|
|
1025
992
|
# Check if either node is ErrorProxyNode and mark connection modification (deletes are always user-initiated)
|
|
1026
993
|
if isinstance(source_node, ErrorProxyNode):
|
|
@@ -1028,16 +995,14 @@ class FlowManager:
|
|
|
1028
995
|
if isinstance(target_node, ErrorProxyNode):
|
|
1029
996
|
target_node.set_post_init_connections_modified()
|
|
1030
997
|
|
|
1031
|
-
result = DeleteConnectionResultSuccess()
|
|
998
|
+
result = DeleteConnectionResultSuccess(result_details=details)
|
|
1032
999
|
return result
|
|
1033
1000
|
|
|
1034
1001
|
async def on_start_flow_request(self, request: StartFlowRequest) -> ResultPayload: # noqa: C901, PLR0911, PLR0912
|
|
1035
1002
|
# which flow
|
|
1036
1003
|
flow_name = request.flow_name
|
|
1037
|
-
debug_mode = request.debug_mode
|
|
1038
1004
|
if not flow_name:
|
|
1039
1005
|
details = "Must provide flow name to start a flow."
|
|
1040
|
-
logger.error(details)
|
|
1041
1006
|
|
|
1042
1007
|
return StartFlowResultFailure(validation_exceptions=[], result_details=details)
|
|
1043
1008
|
# get the flow by ID
|
|
@@ -1045,12 +1010,10 @@ class FlowManager:
|
|
|
1045
1010
|
flow = self.get_flow_by_name(flow_name)
|
|
1046
1011
|
except KeyError as err:
|
|
1047
1012
|
details = f"Cannot start flow. Error: {err}"
|
|
1048
|
-
logger.error(details)
|
|
1049
1013
|
return StartFlowResultFailure(validation_exceptions=[err], result_details=details)
|
|
1050
1014
|
# Check to see if the flow is already running.
|
|
1051
1015
|
if self.check_for_existing_running_flow():
|
|
1052
1016
|
details = "Cannot start flow. Flow is already running."
|
|
1053
|
-
logger.error(details)
|
|
1054
1017
|
return StartFlowResultFailure(validation_exceptions=[], result_details=details)
|
|
1055
1018
|
# A node has been provided to either start or to run up to.
|
|
1056
1019
|
if request.flow_node_name:
|
|
@@ -1058,14 +1021,12 @@ class FlowManager:
|
|
|
1058
1021
|
flow_node = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(flow_node_name, BaseNode)
|
|
1059
1022
|
if not flow_node:
|
|
1060
1023
|
details = f"Provided node with name {flow_node_name} does not exist"
|
|
1061
|
-
logger.error(details)
|
|
1062
1024
|
return StartFlowResultFailure(validation_exceptions=[], result_details=details)
|
|
1063
1025
|
# lets get the first control node in the flow!
|
|
1064
1026
|
start_node = self.get_start_node_from_node(flow, flow_node)
|
|
1065
1027
|
# if the start is not the node provided, set a breakpoint at the stop (we're running up until there)
|
|
1066
1028
|
if not start_node:
|
|
1067
1029
|
details = f"Start node for node with name {flow_node_name} does not exist"
|
|
1068
|
-
logger.error(details)
|
|
1069
1030
|
return StartFlowResultFailure(validation_exceptions=[], result_details=details)
|
|
1070
1031
|
if start_node != flow_node:
|
|
1071
1032
|
flow_node.stop_flow = True
|
|
@@ -1081,8 +1042,7 @@ class FlowManager:
|
|
|
1081
1042
|
try:
|
|
1082
1043
|
if not result.succeeded():
|
|
1083
1044
|
details = f"Couldn't start flow with name {flow_name}. Flow Validation Failed"
|
|
1084
|
-
|
|
1085
|
-
return StartFlowResultFailure(validation_exceptions=[])
|
|
1045
|
+
return StartFlowResultFailure(validation_exceptions=[], result_details=details)
|
|
1086
1046
|
result = cast("ValidateFlowDependenciesResultSuccess", result)
|
|
1087
1047
|
|
|
1088
1048
|
if not result.validation_succeeded:
|
|
@@ -1090,36 +1050,30 @@ class FlowManager:
|
|
|
1090
1050
|
if len(result.exceptions) > 0:
|
|
1091
1051
|
for exception in result.exceptions:
|
|
1092
1052
|
details = f"{details}\n\t{exception}"
|
|
1093
|
-
logger.error(details)
|
|
1094
1053
|
return StartFlowResultFailure(validation_exceptions=result.exceptions, result_details=details)
|
|
1095
1054
|
except Exception as e:
|
|
1096
1055
|
details = f"Couldn't start flow with name {flow_name}. Flow Validation Failed: {e}"
|
|
1097
|
-
logger.error(details)
|
|
1098
1056
|
return StartFlowResultFailure(validation_exceptions=[e], result_details=details)
|
|
1099
1057
|
# By now, it has been validated with no exceptions.
|
|
1100
1058
|
try:
|
|
1101
|
-
await self.start_flow(flow, start_node, debug_mode)
|
|
1059
|
+
await self.start_flow(flow, start_node, debug_mode=request.debug_mode)
|
|
1102
1060
|
except Exception as e:
|
|
1103
1061
|
details = f"Failed to kick off flow with name {flow_name}. Exception occurred: {e} "
|
|
1104
|
-
logger.error(details)
|
|
1105
1062
|
return StartFlowResultFailure(validation_exceptions=[e], result_details=details)
|
|
1106
1063
|
|
|
1107
1064
|
details = f"Successfully kicked off flow with name {flow_name}"
|
|
1108
|
-
logger.debug(details)
|
|
1109
1065
|
|
|
1110
|
-
return StartFlowResultSuccess()
|
|
1066
|
+
return StartFlowResultSuccess(result_details=details)
|
|
1111
1067
|
|
|
1112
1068
|
def on_get_flow_state_request(self, event: GetFlowStateRequest) -> ResultPayload:
|
|
1113
1069
|
flow_name = event.flow_name
|
|
1114
1070
|
if not flow_name:
|
|
1115
1071
|
details = "Could not get flow state. No flow name was provided."
|
|
1116
|
-
logger.error(details)
|
|
1117
1072
|
return GetFlowStateResultFailure(result_details=details)
|
|
1118
1073
|
try:
|
|
1119
1074
|
flow = self.get_flow_by_name(flow_name)
|
|
1120
1075
|
except KeyError as err:
|
|
1121
1076
|
details = f"Could not get flow state. Error: {err}"
|
|
1122
|
-
logger.error(details)
|
|
1123
1077
|
return GetFlowStateResultFailure(result_details=details)
|
|
1124
1078
|
try:
|
|
1125
1079
|
control_node, resolving_node = self.flow_state(flow)
|
|
@@ -1128,47 +1082,42 @@ class FlowManager:
|
|
|
1128
1082
|
logger.exception(details)
|
|
1129
1083
|
return GetFlowStateResultFailure(result_details=details)
|
|
1130
1084
|
details = f"Successfully got flow state for flow with name {flow_name}."
|
|
1131
|
-
|
|
1132
|
-
|
|
1085
|
+
return GetFlowStateResultSuccess(
|
|
1086
|
+
control_node=control_node, resolving_node=resolving_node, result_details=details
|
|
1087
|
+
)
|
|
1133
1088
|
|
|
1134
1089
|
def on_cancel_flow_request(self, request: CancelFlowRequest) -> ResultPayload:
|
|
1135
1090
|
flow_name = request.flow_name
|
|
1136
1091
|
if not flow_name:
|
|
1137
1092
|
details = "Could not cancel flow execution. No flow name was provided."
|
|
1138
|
-
logger.error(details)
|
|
1139
1093
|
|
|
1140
1094
|
return CancelFlowResultFailure(result_details=details)
|
|
1141
1095
|
try:
|
|
1142
1096
|
self.get_flow_by_name(flow_name)
|
|
1143
1097
|
except KeyError as err:
|
|
1144
1098
|
details = f"Could not cancel flow execution. Error: {err}"
|
|
1145
|
-
logger.error(details)
|
|
1146
1099
|
|
|
1147
1100
|
return CancelFlowResultFailure(result_details=details)
|
|
1148
1101
|
try:
|
|
1149
1102
|
self.cancel_flow_run()
|
|
1150
1103
|
except Exception as e:
|
|
1151
1104
|
details = f"Could not cancel flow execution. Exception: {e}"
|
|
1152
|
-
logger.error(details)
|
|
1153
1105
|
|
|
1154
1106
|
return CancelFlowResultFailure(result_details=details)
|
|
1155
1107
|
details = f"Successfully cancelled flow execution with name {flow_name}"
|
|
1156
|
-
logger.debug(details)
|
|
1157
1108
|
|
|
1158
|
-
return CancelFlowResultSuccess()
|
|
1109
|
+
return CancelFlowResultSuccess(result_details=details)
|
|
1159
1110
|
|
|
1160
1111
|
async def on_single_node_step_request(self, request: SingleNodeStepRequest) -> ResultPayload:
|
|
1161
1112
|
flow_name = request.flow_name
|
|
1162
1113
|
if not flow_name:
|
|
1163
1114
|
details = "Could not advance to the next step of a running workflow. No flow name was provided."
|
|
1164
|
-
logger.error(details)
|
|
1165
1115
|
|
|
1166
1116
|
return SingleNodeStepResultFailure(validation_exceptions=[], result_details=details)
|
|
1167
1117
|
try:
|
|
1168
1118
|
self.get_flow_by_name(flow_name)
|
|
1169
1119
|
except KeyError as err:
|
|
1170
1120
|
details = f"Could not advance to the next step of a running workflow. No flow with name {flow_name} exists. Error: {err}"
|
|
1171
|
-
logger.error(details)
|
|
1172
1121
|
|
|
1173
1122
|
return SingleNodeStepResultFailure(validation_exceptions=[err], result_details=details)
|
|
1174
1123
|
try:
|
|
@@ -1176,27 +1125,23 @@ class FlowManager:
|
|
|
1176
1125
|
await self.single_node_step(flow)
|
|
1177
1126
|
except Exception as e:
|
|
1178
1127
|
details = f"Could not advance to the next step of a running workflow. Exception: {e}"
|
|
1179
|
-
logger.error(details)
|
|
1180
1128
|
return SingleNodeStepResultFailure(validation_exceptions=[], result_details=details)
|
|
1181
1129
|
|
|
1182
1130
|
# All completed happily
|
|
1183
1131
|
details = f"Successfully advanced to the next step of a running workflow with name {flow_name}"
|
|
1184
|
-
logger.debug(details)
|
|
1185
1132
|
|
|
1186
|
-
return SingleNodeStepResultSuccess()
|
|
1133
|
+
return SingleNodeStepResultSuccess(result_details=details)
|
|
1187
1134
|
|
|
1188
1135
|
async def on_single_execution_step_request(self, request: SingleExecutionStepRequest) -> ResultPayload:
|
|
1189
1136
|
flow_name = request.flow_name
|
|
1190
1137
|
if not flow_name:
|
|
1191
1138
|
details = "Could not advance to the next step of a running workflow. No flow name was provided."
|
|
1192
|
-
logger.error(details)
|
|
1193
1139
|
|
|
1194
1140
|
return SingleExecutionStepResultFailure(result_details=details)
|
|
1195
1141
|
try:
|
|
1196
1142
|
flow = self.get_flow_by_name(flow_name)
|
|
1197
1143
|
except KeyError as err:
|
|
1198
1144
|
details = f"Could not advance to the next step of a running workflow. Error: {err}."
|
|
1199
|
-
logger.error(details)
|
|
1200
1145
|
|
|
1201
1146
|
return SingleExecutionStepResultFailure(result_details=details)
|
|
1202
1147
|
change_debug_mode = request.request_id is not None
|
|
@@ -1209,61 +1154,50 @@ class FlowManager:
|
|
|
1209
1154
|
self.cancel_flow_run()
|
|
1210
1155
|
except Exception as e_inner:
|
|
1211
1156
|
details = f"Could not cancel flow execution. Exception: {e_inner}"
|
|
1212
|
-
logger.error(details)
|
|
1213
1157
|
|
|
1214
1158
|
details = f"Could not advance to the next step of a running workflow. Exception: {e}"
|
|
1215
|
-
logger.error(details)
|
|
1216
1159
|
return SingleNodeStepResultFailure(validation_exceptions=[e], result_details=details)
|
|
1217
1160
|
details = f"Successfully advanced to the next step of a running workflow with name {flow_name}"
|
|
1218
|
-
logger.debug(details)
|
|
1219
1161
|
|
|
1220
|
-
return SingleExecutionStepResultSuccess()
|
|
1162
|
+
return SingleExecutionStepResultSuccess(result_details=details)
|
|
1221
1163
|
|
|
1222
1164
|
async def on_continue_execution_step_request(self, request: ContinueExecutionStepRequest) -> ResultPayload:
|
|
1223
1165
|
flow_name = request.flow_name
|
|
1224
1166
|
if not flow_name:
|
|
1225
1167
|
details = "Failed to continue execution step because no flow name was provided"
|
|
1226
|
-
logger.error(details)
|
|
1227
1168
|
|
|
1228
1169
|
return ContinueExecutionStepResultFailure(result_details=details)
|
|
1229
1170
|
try:
|
|
1230
1171
|
flow = self.get_flow_by_name(flow_name)
|
|
1231
1172
|
except KeyError as err:
|
|
1232
1173
|
details = f"Failed to continue execution step. Error: {err}"
|
|
1233
|
-
logger.error(details)
|
|
1234
1174
|
|
|
1235
1175
|
return ContinueExecutionStepResultFailure(result_details=details)
|
|
1236
1176
|
try:
|
|
1237
1177
|
await self.continue_executing(flow)
|
|
1238
1178
|
except Exception as e:
|
|
1239
1179
|
details = f"Failed to continue execution step. An exception occurred: {e}."
|
|
1240
|
-
logger.error(details)
|
|
1241
1180
|
return ContinueExecutionStepResultFailure(result_details=details)
|
|
1242
1181
|
details = f"Successfully continued flow with name {flow_name}"
|
|
1243
|
-
|
|
1244
|
-
return ContinueExecutionStepResultSuccess()
|
|
1182
|
+
return ContinueExecutionStepResultSuccess(result_details=details)
|
|
1245
1183
|
|
|
1246
1184
|
def on_unresolve_flow_request(self, request: UnresolveFlowRequest) -> ResultPayload:
|
|
1247
1185
|
flow_name = request.flow_name
|
|
1248
1186
|
if not flow_name:
|
|
1249
1187
|
details = "Failed to unresolve flow because no flow name was provided"
|
|
1250
|
-
logger.error(details)
|
|
1251
1188
|
return UnresolveFlowResultFailure(result_details=details)
|
|
1252
1189
|
try:
|
|
1253
1190
|
flow = self.get_flow_by_name(flow_name)
|
|
1254
1191
|
except KeyError as err:
|
|
1255
1192
|
details = f"Failed to unresolve flow. Error: {err}"
|
|
1256
|
-
logger.error(details)
|
|
1257
1193
|
return UnresolveFlowResultFailure(result_details=details)
|
|
1258
1194
|
try:
|
|
1259
1195
|
self.unresolve_whole_flow(flow)
|
|
1260
1196
|
except Exception as e:
|
|
1261
1197
|
details = f"Failed to unresolve flow. An exception occurred: {e}."
|
|
1262
|
-
logger.error(details)
|
|
1263
1198
|
return UnresolveFlowResultFailure(result_details=details)
|
|
1264
1199
|
details = f"Unresolved flow with name {flow_name}"
|
|
1265
|
-
|
|
1266
|
-
return UnresolveFlowResultSuccess()
|
|
1200
|
+
return UnresolveFlowResultSuccess(result_details=details)
|
|
1267
1201
|
|
|
1268
1202
|
async def on_validate_flow_dependencies_request(self, request: ValidateFlowDependenciesRequest) -> ResultPayload:
|
|
1269
1203
|
flow_name = request.flow_name
|
|
@@ -1272,14 +1206,12 @@ class FlowManager:
|
|
|
1272
1206
|
flow = self.get_flow_by_name(flow_name)
|
|
1273
1207
|
except KeyError as err:
|
|
1274
1208
|
details = f"Failed to validate flow. Error: {err}"
|
|
1275
|
-
logger.error(details)
|
|
1276
1209
|
return ValidateFlowDependenciesResultFailure(result_details=details)
|
|
1277
1210
|
if request.flow_node_name:
|
|
1278
1211
|
flow_node_name = request.flow_node_name
|
|
1279
1212
|
flow_node = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(flow_node_name, BaseNode)
|
|
1280
1213
|
if not flow_node:
|
|
1281
1214
|
details = f"Provided node with name {flow_node_name} does not exist"
|
|
1282
|
-
logger.error(details)
|
|
1283
1215
|
return ValidateFlowDependenciesResultFailure(result_details=details)
|
|
1284
1216
|
# Gets all nodes in that connected group to be ran
|
|
1285
1217
|
nodes = flow.get_all_connected_nodes(flow_node)
|
|
@@ -1292,13 +1224,14 @@ class FlowManager:
|
|
|
1292
1224
|
if exceptions:
|
|
1293
1225
|
all_exceptions = all_exceptions + exceptions
|
|
1294
1226
|
return ValidateFlowDependenciesResultSuccess(
|
|
1295
|
-
validation_succeeded=len(all_exceptions) == 0,
|
|
1227
|
+
validation_succeeded=len(all_exceptions) == 0,
|
|
1228
|
+
exceptions=all_exceptions,
|
|
1229
|
+
result_details=f"Validated flow dependencies: {len(all_exceptions)} exceptions found",
|
|
1296
1230
|
)
|
|
1297
1231
|
|
|
1298
1232
|
def on_list_flows_in_current_context_request(self, request: ListFlowsInCurrentContextRequest) -> ResultPayload: # noqa: ARG002 (request isn't actually used)
|
|
1299
1233
|
if not GriptapeNodes.ContextManager().has_current_flow():
|
|
1300
1234
|
details = "Attempted to list Flows in the Current Context. Failed because the Current Context was empty."
|
|
1301
|
-
logger.error(details)
|
|
1302
1235
|
return ListFlowsInCurrentContextResultFailure(result_details=details)
|
|
1303
1236
|
|
|
1304
1237
|
parent_flow = GriptapeNodes.ContextManager().get_current_flow()
|
|
@@ -1311,9 +1244,8 @@ class FlowManager:
|
|
|
1311
1244
|
ret_list.append(flow_name)
|
|
1312
1245
|
|
|
1313
1246
|
details = f"Successfully got the list of Flows in the Current Context (Flow '{parent_flow_name}')."
|
|
1314
|
-
logger.debug(details)
|
|
1315
1247
|
|
|
1316
|
-
return ListFlowsInCurrentContextResultSuccess(flow_names=ret_list)
|
|
1248
|
+
return ListFlowsInCurrentContextResultSuccess(flow_names=ret_list, result_details=details)
|
|
1317
1249
|
|
|
1318
1250
|
# TODO: https://github.com/griptape-ai/griptape-nodes/issues/861
|
|
1319
1251
|
# similar manager refactors: https://github.com/griptape-ai/griptape-nodes/issues/806
|
|
@@ -1326,7 +1258,6 @@ class FlowManager:
|
|
|
1326
1258
|
flow_name = flow.name
|
|
1327
1259
|
else:
|
|
1328
1260
|
details = "Attempted to serialize a Flow to commands from the Current Context. Failed because the Current Context was empty."
|
|
1329
|
-
logger.error(details)
|
|
1330
1261
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1331
1262
|
if flow is None:
|
|
1332
1263
|
# Does this flow exist?
|
|
@@ -1335,7 +1266,6 @@ class FlowManager:
|
|
|
1335
1266
|
details = (
|
|
1336
1267
|
f"Attempted to serialize Flow '{flow_name}' to commands, but no Flow with that name could be found."
|
|
1337
1268
|
)
|
|
1338
|
-
logger.error(details)
|
|
1339
1269
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1340
1270
|
|
|
1341
1271
|
# Track all node libraries that were in use by these Nodes
|
|
@@ -1381,7 +1311,6 @@ class FlowManager:
|
|
|
1381
1311
|
details = (
|
|
1382
1312
|
f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to list Nodes in the Flow."
|
|
1383
1313
|
)
|
|
1384
|
-
logger.error(details)
|
|
1385
1314
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1386
1315
|
|
|
1387
1316
|
# Serialize each node
|
|
@@ -1389,7 +1318,6 @@ class FlowManager:
|
|
|
1389
1318
|
node = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(node_name, BaseNode)
|
|
1390
1319
|
if node is None:
|
|
1391
1320
|
details = f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to serialize Node '{node_name}' within the Flow."
|
|
1392
|
-
logger.error(details)
|
|
1393
1321
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1394
1322
|
with GriptapeNodes.ContextManager().node(node):
|
|
1395
1323
|
# Note: the parameter value stuff is pass-by-reference, and we expect the values to be modified in place.
|
|
@@ -1401,7 +1329,6 @@ class FlowManager:
|
|
|
1401
1329
|
serialize_node_result = GriptapeNodes.handle_request(serialize_node_request)
|
|
1402
1330
|
if not isinstance(serialize_node_result, SerializeNodeToCommandsResultSuccess):
|
|
1403
1331
|
details = f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to serialize Node '{node_name}' within the Flow."
|
|
1404
|
-
logger.error(details)
|
|
1405
1332
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1406
1333
|
|
|
1407
1334
|
serialized_node = serialize_node_result.serialized_node_commands
|
|
@@ -1441,7 +1368,6 @@ class FlowManager:
|
|
|
1441
1368
|
flows_in_flow_result = GriptapeNodes().handle_request(flows_in_flow_request)
|
|
1442
1369
|
if not isinstance(flows_in_flow_result, ListFlowsInFlowResultSuccess):
|
|
1443
1370
|
details = f"Attempted to serialize Flow '{flow_name}'. Failed while attempting to list child Flows in the Flow."
|
|
1444
|
-
logger.error(details)
|
|
1445
1371
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1446
1372
|
|
|
1447
1373
|
sub_flow_commands = []
|
|
@@ -1449,7 +1375,6 @@ class FlowManager:
|
|
|
1449
1375
|
flow = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(child_flow, ControlFlow)
|
|
1450
1376
|
if flow is None:
|
|
1451
1377
|
details = f"Attempted to serialize Flow '{flow_name}', but no Flow with that name could be found."
|
|
1452
|
-
logger.error(details)
|
|
1453
1378
|
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1454
1379
|
|
|
1455
1380
|
# Check if this is a referenced workflow
|
|
@@ -1482,8 +1407,7 @@ class FlowManager:
|
|
|
1482
1407
|
child_flow_result = GriptapeNodes().handle_request(child_flow_request)
|
|
1483
1408
|
if not isinstance(child_flow_result, SerializeFlowToCommandsResultSuccess):
|
|
1484
1409
|
details = f"Attempted to serialize parent flow '{flow_name}'. Failed while serializing child flow '{child_flow}'."
|
|
1485
|
-
|
|
1486
|
-
return SerializeFlowToCommandsResultFailure()
|
|
1410
|
+
return SerializeFlowToCommandsResultFailure(result_details=details)
|
|
1487
1411
|
serialized_flow = child_flow_result.serialized_flow_commands
|
|
1488
1412
|
sub_flow_commands.append(serialized_flow)
|
|
1489
1413
|
|
|
@@ -1505,7 +1429,7 @@ class FlowManager:
|
|
|
1505
1429
|
referenced_workflows=referenced_workflows_in_use,
|
|
1506
1430
|
)
|
|
1507
1431
|
details = f"Successfully serialized Flow '{flow_name}' into commands."
|
|
1508
|
-
result = SerializeFlowToCommandsResultSuccess(serialized_flow_commands=serialized_flow)
|
|
1432
|
+
result = SerializeFlowToCommandsResultSuccess(serialized_flow_commands=serialized_flow, result_details=details)
|
|
1509
1433
|
return result
|
|
1510
1434
|
|
|
1511
1435
|
def on_deserialize_flow_from_commands(self, request: DeserializeFlowFromCommandsRequest) -> ResultPayload: # noqa: C901, PLR0911, PLR0912, PLR0915 (I am big and complicated and have a lot of negative edge-cases)
|
|
@@ -1516,7 +1440,6 @@ class FlowManager:
|
|
|
1516
1440
|
flow_name = flow.name
|
|
1517
1441
|
else:
|
|
1518
1442
|
details = "Attempted to deserialize a set of Flow Creation commands into the Current Context. Failed because the Current Context was empty."
|
|
1519
|
-
logger.error(details)
|
|
1520
1443
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1521
1444
|
else:
|
|
1522
1445
|
# Issue the creation command first.
|
|
@@ -1528,25 +1451,21 @@ class FlowManager:
|
|
|
1528
1451
|
case CreateFlowRequest():
|
|
1529
1452
|
if not isinstance(flow_initialization_result, CreateFlowResultSuccess):
|
|
1530
1453
|
details = f"Attempted to deserialize a serialized set of Flow Creation commands. Failed to create flow '{flow_initialization_command.flow_name}'."
|
|
1531
|
-
logger.error(details)
|
|
1532
1454
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1533
1455
|
flow_name = flow_initialization_result.flow_name
|
|
1534
1456
|
case ImportWorkflowAsReferencedSubFlowRequest():
|
|
1535
1457
|
if not isinstance(flow_initialization_result, ImportWorkflowAsReferencedSubFlowResultSuccess):
|
|
1536
1458
|
details = f"Attempted to deserialize a serialized set of Flow Creation commands. Failed to import workflow '{flow_initialization_command.workflow_name}'."
|
|
1537
|
-
logger.error(details)
|
|
1538
1459
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1539
1460
|
flow_name = flow_initialization_result.created_flow_name
|
|
1540
1461
|
case _:
|
|
1541
1462
|
details = f"Attempted to deserialize Flow Creation commands with unknown command type: {type(flow_initialization_command).__name__}."
|
|
1542
|
-
logger.error(details)
|
|
1543
1463
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1544
1464
|
|
|
1545
1465
|
# Adopt the newly-created flow as our current context.
|
|
1546
1466
|
flow = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(flow_name, ControlFlow)
|
|
1547
1467
|
if flow is None:
|
|
1548
1468
|
details = f"Attempted to deserialize a serialized set of Flow Creation commands. Failed to find created flow '{flow_name}'."
|
|
1549
|
-
logger.error(details)
|
|
1550
1469
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1551
1470
|
GriptapeNodes.ContextManager().push_flow(flow=flow)
|
|
1552
1471
|
|
|
@@ -1562,7 +1481,6 @@ class FlowManager:
|
|
|
1562
1481
|
details = (
|
|
1563
1482
|
f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a node within the flow."
|
|
1564
1483
|
)
|
|
1565
|
-
logger.error(details)
|
|
1566
1484
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1567
1485
|
node_uuid_to_deserialized_node_result[serialized_node.node_uuid] = deserialized_node_result
|
|
1568
1486
|
|
|
@@ -1574,12 +1492,10 @@ class FlowManager:
|
|
|
1574
1492
|
source_node_uuid = indirect_connection.source_node_uuid
|
|
1575
1493
|
if source_node_uuid not in node_uuid_to_deserialized_node_result:
|
|
1576
1494
|
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."
|
|
1577
|
-
logger.error(details)
|
|
1578
1495
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1579
1496
|
target_node_uuid = indirect_connection.target_node_uuid
|
|
1580
1497
|
if target_node_uuid not in node_uuid_to_deserialized_node_result:
|
|
1581
1498
|
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."
|
|
1582
|
-
logger.error(details)
|
|
1583
1499
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1584
1500
|
|
|
1585
1501
|
source_node_result = node_uuid_to_deserialized_node_result[source_node_uuid]
|
|
@@ -1596,7 +1512,6 @@ class FlowManager:
|
|
|
1596
1512
|
create_connection_result = GriptapeNodes.handle_request(create_connection_request)
|
|
1597
1513
|
if create_connection_result.failed():
|
|
1598
1514
|
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."
|
|
1599
|
-
logger.error(details)
|
|
1600
1515
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1601
1516
|
|
|
1602
1517
|
# Now assign the values.
|
|
@@ -1610,7 +1525,6 @@ class FlowManager:
|
|
|
1610
1525
|
node = GriptapeNodes.ObjectManager().attempt_get_object_by_name_as_type(node_name, BaseNode)
|
|
1611
1526
|
if node is None:
|
|
1612
1527
|
details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a value assignment for node '{node_name}'."
|
|
1613
|
-
logger.error(details)
|
|
1614
1528
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1615
1529
|
with GriptapeNodes.ContextManager().node(node=node):
|
|
1616
1530
|
# Iterate through each set value command in the list for this node.
|
|
@@ -1621,7 +1535,6 @@ class FlowManager:
|
|
|
1621
1535
|
value = request.serialized_flow_commands.unique_parameter_uuid_to_values[unique_value_uuid]
|
|
1622
1536
|
except IndexError as err:
|
|
1623
1537
|
details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a value assignment for node '{node.name}.{parameter_name}': {err}"
|
|
1624
|
-
logger.error(details)
|
|
1625
1538
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1626
1539
|
|
|
1627
1540
|
# Call the SetParameterValueRequest, subbing in the value from our unique value list.
|
|
@@ -1631,7 +1544,6 @@ class FlowManager:
|
|
|
1631
1544
|
)
|
|
1632
1545
|
if set_parameter_value_result.failed():
|
|
1633
1546
|
details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a value assignment for node '{node.name}.{parameter_name}'."
|
|
1634
|
-
logger.error(details)
|
|
1635
1547
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1636
1548
|
|
|
1637
1549
|
# Now the child flows.
|
|
@@ -1640,12 +1552,10 @@ class FlowManager:
|
|
|
1640
1552
|
sub_flow_result = GriptapeNodes.handle_request(sub_flow_request)
|
|
1641
1553
|
if sub_flow_result.failed():
|
|
1642
1554
|
details = f"Attempted to deserialize a Flow '{flow_name}'. Failed while deserializing a sub-flow within the Flow."
|
|
1643
|
-
logger.error(details)
|
|
1644
1555
|
return DeserializeFlowFromCommandsResultFailure(result_details=details)
|
|
1645
1556
|
|
|
1646
1557
|
details = f"Successfully deserialized Flow '{flow_name}'."
|
|
1647
|
-
|
|
1648
|
-
return DeserializeFlowFromCommandsResultSuccess(flow_name=flow_name)
|
|
1558
|
+
return DeserializeFlowFromCommandsResultSuccess(flow_name=flow_name, result_details=details)
|
|
1649
1559
|
|
|
1650
1560
|
def on_flush_request(self, request: FlushParameterChangesRequest) -> ResultPayload: # noqa: ARG002
|
|
1651
1561
|
obj_manager = GriptapeNodes.ObjectManager()
|
|
@@ -1656,9 +1566,15 @@ class FlowManager:
|
|
|
1656
1566
|
# Only flush if there are actually tracked parameters
|
|
1657
1567
|
if node._tracked_parameters:
|
|
1658
1568
|
node.emit_parameter_changes()
|
|
1659
|
-
return FlushParameterChangesResultSuccess()
|
|
1569
|
+
return FlushParameterChangesResultSuccess(result_details="Parameter changes flushed successfully.")
|
|
1660
1570
|
|
|
1661
|
-
async def start_flow(
|
|
1571
|
+
async def start_flow(
|
|
1572
|
+
self,
|
|
1573
|
+
flow: ControlFlow,
|
|
1574
|
+
start_node: BaseNode | None = None,
|
|
1575
|
+
*,
|
|
1576
|
+
debug_mode: bool = False,
|
|
1577
|
+
) -> None:
|
|
1662
1578
|
if self.check_for_existing_running_flow():
|
|
1663
1579
|
# If flow already exists, throw an error
|
|
1664
1580
|
errormsg = "This workflow is already in progress. Please wait for the current process to finish before starting again."
|
|
@@ -1668,13 +1584,12 @@ class FlowManager:
|
|
|
1668
1584
|
if self._global_flow_queue.empty():
|
|
1669
1585
|
errormsg = "No Flow exists. You must create at least one control connection."
|
|
1670
1586
|
raise RuntimeError(errormsg)
|
|
1671
|
-
|
|
1587
|
+
queue_item = self._global_flow_queue.get()
|
|
1588
|
+
start_node = queue_item.node
|
|
1672
1589
|
self._global_flow_queue.task_done()
|
|
1673
1590
|
|
|
1674
1591
|
# Initialize global control flow machine if needed
|
|
1675
|
-
|
|
1676
|
-
self._global_control_flow_machine = ControlFlowMachine()
|
|
1677
|
-
|
|
1592
|
+
self._global_control_flow_machine = ControlFlowMachine(flow.name)
|
|
1678
1593
|
try:
|
|
1679
1594
|
await self._global_control_flow_machine.start_flow(start_node, debug_mode)
|
|
1680
1595
|
except Exception:
|
|
@@ -1685,15 +1600,13 @@ class FlowManager:
|
|
|
1685
1600
|
def check_for_existing_running_flow(self) -> bool:
|
|
1686
1601
|
if self._global_control_flow_machine is None:
|
|
1687
1602
|
return False
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
and self._global_control_flow_machine._current_state
|
|
1691
|
-
):
|
|
1603
|
+
current_state = self._global_control_flow_machine.current_state
|
|
1604
|
+
if current_state and current_state is not CompleteState:
|
|
1692
1605
|
# Flow already exists in progress
|
|
1693
1606
|
return True
|
|
1694
1607
|
return bool(
|
|
1695
|
-
not self._global_control_flow_machine.
|
|
1696
|
-
and self._global_control_flow_machine.
|
|
1608
|
+
not self._global_control_flow_machine.context.resolution_machine.is_complete()
|
|
1609
|
+
and self._global_control_flow_machine.context.resolution_machine.is_started()
|
|
1697
1610
|
)
|
|
1698
1611
|
|
|
1699
1612
|
def cancel_flow_run(self) -> None:
|
|
@@ -1701,9 +1614,9 @@ class FlowManager:
|
|
|
1701
1614
|
errormsg = "Flow has not yet been started. Cannot cancel flow that hasn't begun."
|
|
1702
1615
|
raise RuntimeError(errormsg)
|
|
1703
1616
|
self._global_flow_queue.queue.clear()
|
|
1704
|
-
if self._global_control_flow_machine is not None:
|
|
1705
|
-
self._global_control_flow_machine.reset_machine()
|
|
1706
1617
|
# Reset control flow machine
|
|
1618
|
+
if self._global_control_flow_machine is not None:
|
|
1619
|
+
self._global_control_flow_machine.reset_machine(cancel=True)
|
|
1707
1620
|
self._global_single_node_resolution = False
|
|
1708
1621
|
logger.debug("Cancelling flow run")
|
|
1709
1622
|
|
|
@@ -1716,7 +1629,7 @@ class FlowManager:
|
|
|
1716
1629
|
self._global_flow_queue.queue.clear()
|
|
1717
1630
|
if self._global_control_flow_machine is not None:
|
|
1718
1631
|
self._global_control_flow_machine.reset_machine()
|
|
1719
|
-
|
|
1632
|
+
# Reset control flow machine
|
|
1720
1633
|
self._global_single_node_resolution = False
|
|
1721
1634
|
|
|
1722
1635
|
# Clear all connections to prevent memory leaks and stale references
|
|
@@ -1735,9 +1648,9 @@ class FlowManager:
|
|
|
1735
1648
|
"""Get the next node from the global execution queue, or None if empty."""
|
|
1736
1649
|
if self._global_flow_queue.empty():
|
|
1737
1650
|
return None
|
|
1738
|
-
|
|
1651
|
+
queue_item = self._global_flow_queue.get()
|
|
1739
1652
|
self._global_flow_queue.task_done()
|
|
1740
|
-
return node
|
|
1653
|
+
return queue_item.node
|
|
1741
1654
|
|
|
1742
1655
|
def clear_execution_queue(self) -> None:
|
|
1743
1656
|
"""Clear all nodes from the global execution queue."""
|
|
@@ -1756,7 +1669,7 @@ class FlowManager:
|
|
|
1756
1669
|
# Internal execution queue helper methods to consolidate redundant operations
|
|
1757
1670
|
async def _handle_flow_start_if_not_running(
|
|
1758
1671
|
self,
|
|
1759
|
-
flow: ControlFlow,
|
|
1672
|
+
flow: ControlFlow,
|
|
1760
1673
|
*,
|
|
1761
1674
|
debug_mode: bool,
|
|
1762
1675
|
error_message: str,
|
|
@@ -1765,42 +1678,43 @@ class FlowManager:
|
|
|
1765
1678
|
if not self.check_for_existing_running_flow():
|
|
1766
1679
|
if self._global_flow_queue.empty():
|
|
1767
1680
|
raise RuntimeError(error_message)
|
|
1768
|
-
|
|
1681
|
+
queue_item = self._global_flow_queue.get()
|
|
1682
|
+
start_node = queue_item.node
|
|
1769
1683
|
self._global_flow_queue.task_done()
|
|
1684
|
+
# Get or create machine
|
|
1770
1685
|
if self._global_control_flow_machine is None:
|
|
1771
|
-
self._global_control_flow_machine = ControlFlowMachine()
|
|
1686
|
+
self._global_control_flow_machine = ControlFlowMachine(flow.name)
|
|
1772
1687
|
await self._global_control_flow_machine.start_flow(start_node, debug_mode)
|
|
1773
1688
|
|
|
1774
1689
|
async def _handle_post_execution_queue_processing(self, *, debug_mode: bool) -> None:
|
|
1775
1690
|
"""Handle execution queue processing after execution completes."""
|
|
1776
1691
|
if not self.check_for_existing_running_flow() and not self._global_flow_queue.empty():
|
|
1777
|
-
|
|
1692
|
+
queue_item = self._global_flow_queue.get()
|
|
1693
|
+
start_node = queue_item.node
|
|
1778
1694
|
self._global_flow_queue.task_done()
|
|
1779
|
-
|
|
1780
|
-
|
|
1695
|
+
machine = self._global_control_flow_machine
|
|
1696
|
+
if machine is not None:
|
|
1697
|
+
await machine.start_flow(start_node, debug_mode)
|
|
1781
1698
|
|
|
1782
|
-
async def resolve_singular_node(self, flow: ControlFlow, node: BaseNode, debug_mode: bool = False) -> None:
|
|
1699
|
+
async def resolve_singular_node(self, flow: ControlFlow, node: BaseNode, *, debug_mode: bool = False) -> None:
|
|
1783
1700
|
# Set that we are only working on one node right now! no other stepping allowed
|
|
1784
1701
|
if self.check_for_existing_running_flow():
|
|
1785
1702
|
# If flow already exists, throw an error
|
|
1786
1703
|
errormsg = f"This workflow is already in progress. Please wait for the current process to finish before starting {node.name} again."
|
|
1787
1704
|
raise RuntimeError(errormsg)
|
|
1788
1705
|
self._global_single_node_resolution = True
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
self._global_control_flow_machine.
|
|
1794
|
-
resolution_machine
|
|
1795
|
-
# Set debug mode
|
|
1796
|
-
resolution_machine.change_debug_mode(debug_mode)
|
|
1797
|
-
# Resolve the node.
|
|
1706
|
+
|
|
1707
|
+
# Get or create machine
|
|
1708
|
+
self._global_control_flow_machine = ControlFlowMachine(flow.name)
|
|
1709
|
+
self._global_control_flow_machine.context.current_node = node
|
|
1710
|
+
resolution_machine = self._global_control_flow_machine.resolution_machine
|
|
1711
|
+
resolution_machine.change_debug_mode(debug_mode=debug_mode)
|
|
1798
1712
|
node.state = NodeResolutionState.UNRESOLVED
|
|
1713
|
+
# Resolve the node
|
|
1799
1714
|
await resolution_machine.resolve_node(node)
|
|
1800
|
-
# decide if we can change it back to normal flow mode!
|
|
1801
1715
|
if resolution_machine.is_complete():
|
|
1802
1716
|
self._global_single_node_resolution = False
|
|
1803
|
-
self._global_control_flow_machine.
|
|
1717
|
+
self._global_control_flow_machine.context.current_node = None
|
|
1804
1718
|
|
|
1805
1719
|
async def single_execution_step(self, flow: ControlFlow, change_debug_mode: bool) -> None: # noqa: FBT001
|
|
1806
1720
|
# do a granular step
|
|
@@ -1811,11 +1725,11 @@ class FlowManager:
|
|
|
1811
1725
|
return
|
|
1812
1726
|
if self._global_control_flow_machine is not None:
|
|
1813
1727
|
await self._global_control_flow_machine.granular_step(change_debug_mode)
|
|
1814
|
-
resolution_machine = self._global_control_flow_machine.
|
|
1728
|
+
resolution_machine = self._global_control_flow_machine.resolution_machine
|
|
1815
1729
|
if self._global_single_node_resolution:
|
|
1816
|
-
resolution_machine = self._global_control_flow_machine.
|
|
1817
|
-
|
|
1818
|
-
|
|
1730
|
+
resolution_machine = self._global_control_flow_machine.resolution_machine
|
|
1731
|
+
if resolution_machine.is_complete():
|
|
1732
|
+
self._global_single_node_resolution = False
|
|
1819
1733
|
|
|
1820
1734
|
async def single_node_step(self, flow: ControlFlow) -> None:
|
|
1821
1735
|
# It won't call single_node_step without an existing flow running from US.
|
|
@@ -1840,13 +1754,13 @@ class FlowManager:
|
|
|
1840
1754
|
if not self.check_for_existing_running_flow():
|
|
1841
1755
|
return
|
|
1842
1756
|
# Turn all debugging to false and continue on
|
|
1843
|
-
if self._global_control_flow_machine is not None:
|
|
1757
|
+
if self._global_control_flow_machine is not None and self._global_control_flow_machine is not None:
|
|
1844
1758
|
self._global_control_flow_machine.change_debug_mode(False)
|
|
1845
1759
|
if self._global_single_node_resolution:
|
|
1846
|
-
if self._global_control_flow_machine.
|
|
1760
|
+
if self._global_control_flow_machine.resolution_machine.is_complete():
|
|
1847
1761
|
self._global_single_node_resolution = False
|
|
1848
1762
|
else:
|
|
1849
|
-
await self._global_control_flow_machine.
|
|
1763
|
+
await self._global_control_flow_machine.resolution_machine.update()
|
|
1850
1764
|
else:
|
|
1851
1765
|
await self._global_control_flow_machine.node_step()
|
|
1852
1766
|
# Now it is done executing. make sure it's actually done?
|
|
@@ -1864,12 +1778,11 @@ class FlowManager:
|
|
|
1864
1778
|
raise RuntimeError(msg)
|
|
1865
1779
|
if self._global_control_flow_machine is None:
|
|
1866
1780
|
return None, None
|
|
1781
|
+
control_flow_context = self._global_control_flow_machine.context
|
|
1867
1782
|
current_control_node = (
|
|
1868
|
-
|
|
1869
|
-
if self._global_control_flow_machine._context.current_node is not None
|
|
1870
|
-
else None
|
|
1783
|
+
control_flow_context.current_node.name if control_flow_context.current_node is not None else None
|
|
1871
1784
|
)
|
|
1872
|
-
focus_stack_for_node = self._global_control_flow_machine.
|
|
1785
|
+
focus_stack_for_node = self._global_control_flow_machine.resolution_machine.context.focus_stack
|
|
1873
1786
|
current_resolving_node = focus_stack_for_node[-1].node.name if len(focus_stack_for_node) else None
|
|
1874
1787
|
return current_control_node, current_resolving_node
|
|
1875
1788
|
|
|
@@ -1984,13 +1897,13 @@ class FlowManager:
|
|
|
1984
1897
|
# check if it has an outgoing connection. We don't want it to (that means we get the most resolution)
|
|
1985
1898
|
if node.name not in cn_mgr.outgoing_index:
|
|
1986
1899
|
valid_data_nodes.append(node)
|
|
1987
|
-
# ok now - populate the global flow queue
|
|
1900
|
+
# ok now - populate the global flow queue with node type information
|
|
1988
1901
|
for node in start_nodes:
|
|
1989
|
-
self._global_flow_queue.put(node)
|
|
1902
|
+
self._global_flow_queue.put(QueueItem(node=node, dag_execution_type=DagExecutionType.START_NODE))
|
|
1990
1903
|
for node in control_nodes:
|
|
1991
|
-
self._global_flow_queue.put(node)
|
|
1904
|
+
self._global_flow_queue.put(QueueItem(node=node, dag_execution_type=DagExecutionType.CONTROL_NODE))
|
|
1992
1905
|
for node in valid_data_nodes:
|
|
1993
|
-
self._global_flow_queue.put(node)
|
|
1906
|
+
self._global_flow_queue.put(QueueItem(node=node, dag_execution_type=DagExecutionType.DATA_NODE))
|
|
1994
1907
|
|
|
1995
1908
|
return self._global_flow_queue
|
|
1996
1909
|
|