griptape-nodes 0.52.1__py3-none-any.whl → 0.54.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 +8 -942
- griptape_nodes/__main__.py +6 -0
- griptape_nodes/app/app.py +48 -86
- griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py +35 -5
- griptape_nodes/bootstrap/workflow_executors/workflow_executor.py +15 -1
- griptape_nodes/cli/__init__.py +1 -0
- griptape_nodes/cli/commands/__init__.py +1 -0
- griptape_nodes/cli/commands/config.py +74 -0
- griptape_nodes/cli/commands/engine.py +80 -0
- griptape_nodes/cli/commands/init.py +550 -0
- griptape_nodes/cli/commands/libraries.py +96 -0
- griptape_nodes/cli/commands/models.py +504 -0
- griptape_nodes/cli/commands/self.py +120 -0
- griptape_nodes/cli/main.py +56 -0
- griptape_nodes/cli/shared.py +75 -0
- griptape_nodes/common/__init__.py +1 -0
- griptape_nodes/common/directed_graph.py +71 -0
- griptape_nodes/drivers/storage/base_storage_driver.py +40 -20
- griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +24 -29
- griptape_nodes/drivers/storage/local_storage_driver.py +23 -14
- griptape_nodes/exe_types/core_types.py +60 -2
- griptape_nodes/exe_types/node_types.py +257 -38
- griptape_nodes/exe_types/param_components/__init__.py +1 -0
- griptape_nodes/exe_types/param_components/execution_status_component.py +138 -0
- griptape_nodes/machines/control_flow.py +195 -94
- griptape_nodes/machines/dag_builder.py +207 -0
- griptape_nodes/machines/fsm.py +10 -1
- griptape_nodes/machines/parallel_resolution.py +558 -0
- griptape_nodes/machines/{node_resolution.py → sequential_resolution.py} +30 -57
- griptape_nodes/node_library/library_registry.py +34 -1
- griptape_nodes/retained_mode/events/app_events.py +5 -1
- griptape_nodes/retained_mode/events/base_events.py +9 -9
- griptape_nodes/retained_mode/events/config_events.py +30 -0
- griptape_nodes/retained_mode/events/execution_events.py +2 -2
- griptape_nodes/retained_mode/events/model_events.py +296 -0
- griptape_nodes/retained_mode/events/node_events.py +4 -3
- griptape_nodes/retained_mode/griptape_nodes.py +34 -12
- griptape_nodes/retained_mode/managers/agent_manager.py +23 -5
- griptape_nodes/retained_mode/managers/arbitrary_code_exec_manager.py +3 -1
- griptape_nodes/retained_mode/managers/config_manager.py +44 -3
- griptape_nodes/retained_mode/managers/context_manager.py +6 -5
- griptape_nodes/retained_mode/managers/event_manager.py +8 -2
- griptape_nodes/retained_mode/managers/flow_manager.py +150 -206
- 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/model_manager.py +1107 -0
- griptape_nodes/retained_mode/managers/node_manager.py +102 -220
- griptape_nodes/retained_mode/managers/object_manager.py +11 -5
- griptape_nodes/retained_mode/managers/os_manager.py +28 -13
- griptape_nodes/retained_mode/managers/secrets_manager.py +8 -4
- griptape_nodes/retained_mode/managers/settings.py +116 -7
- griptape_nodes/retained_mode/managers/static_files_manager.py +85 -12
- griptape_nodes/retained_mode/managers/sync_manager.py +17 -9
- griptape_nodes/retained_mode/managers/workflow_manager.py +186 -192
- griptape_nodes/retained_mode/retained_mode.py +19 -0
- griptape_nodes/servers/__init__.py +1 -0
- griptape_nodes/{mcp_server/server.py → servers/mcp.py} +1 -1
- griptape_nodes/{app/api.py → servers/static.py} +43 -40
- griptape_nodes/traits/add_param_button.py +1 -1
- griptape_nodes/traits/button.py +334 -6
- griptape_nodes/traits/color_picker.py +66 -0
- griptape_nodes/traits/multi_options.py +188 -0
- griptape_nodes/traits/numbers_selector.py +77 -0
- griptape_nodes/traits/options.py +93 -2
- griptape_nodes/traits/traits.json +4 -0
- griptape_nodes/utils/async_utils.py +31 -0
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.54.0.dist-info}/METADATA +4 -1
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.54.0.dist-info}/RECORD +71 -48
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.54.0.dist-info}/WHEEL +1 -1
- /griptape_nodes/{mcp_server → servers}/ws_request_manager.py +0 -0
- {griptape_nodes-0.52.1.dist-info → griptape_nodes-0.54.0.dist-info}/entry_points.txt +0 -0
|
@@ -42,6 +42,14 @@ class ResolutionContext:
|
|
|
42
42
|
self.focus_stack = []
|
|
43
43
|
self.paused = False
|
|
44
44
|
|
|
45
|
+
@property
|
|
46
|
+
def current_node(self) -> BaseNode:
|
|
47
|
+
"""Get the currently focused node from the focus stack."""
|
|
48
|
+
if not self.focus_stack:
|
|
49
|
+
msg = "No node is currently in focus - focus stack is empty"
|
|
50
|
+
raise RuntimeError(msg)
|
|
51
|
+
return self.focus_stack[-1].node
|
|
52
|
+
|
|
45
53
|
def reset(self) -> None:
|
|
46
54
|
if self.focus_stack:
|
|
47
55
|
node = self.focus_stack[-1].node
|
|
@@ -55,12 +63,6 @@ class InitializeSpotlightState(State):
|
|
|
55
63
|
@staticmethod
|
|
56
64
|
async def on_enter(context: ResolutionContext) -> type[State] | None:
|
|
57
65
|
# If the focus stack is empty
|
|
58
|
-
current_node = context.focus_stack[-1].node
|
|
59
|
-
GriptapeNodes.EventManager().put_event(
|
|
60
|
-
ExecutionGriptapeNodeEvent(
|
|
61
|
-
wrapped_event=ExecutionEvent(payload=CurrentDataNodeEvent(node_name=current_node.name))
|
|
62
|
-
)
|
|
63
|
-
)
|
|
64
66
|
if not context.paused:
|
|
65
67
|
return InitializeSpotlightState
|
|
66
68
|
return None
|
|
@@ -70,7 +72,7 @@ class InitializeSpotlightState(State):
|
|
|
70
72
|
# If the focus stack is empty
|
|
71
73
|
if not len(context.focus_stack):
|
|
72
74
|
return CompleteState
|
|
73
|
-
current_node = context.
|
|
75
|
+
current_node = context.current_node
|
|
74
76
|
if current_node.state == NodeResolutionState.UNRESOLVED:
|
|
75
77
|
# Mark all future nodes unresolved.
|
|
76
78
|
# TODO: https://github.com/griptape-ai/griptape-nodes/issues/862
|
|
@@ -95,7 +97,7 @@ class InitializeSpotlightState(State):
|
|
|
95
97
|
class EvaluateParameterState(State):
|
|
96
98
|
@staticmethod
|
|
97
99
|
async def on_enter(context: ResolutionContext) -> type[State] | None:
|
|
98
|
-
current_node = context.
|
|
100
|
+
current_node = context.current_node
|
|
99
101
|
current_parameter = current_node.get_current_parameter()
|
|
100
102
|
if current_parameter is None:
|
|
101
103
|
return ExecuteNodeState
|
|
@@ -116,7 +118,7 @@ class EvaluateParameterState(State):
|
|
|
116
118
|
|
|
117
119
|
@staticmethod
|
|
118
120
|
async def on_update(context: ResolutionContext) -> type[State] | None:
|
|
119
|
-
current_node = context.
|
|
121
|
+
current_node = context.current_node
|
|
120
122
|
current_parameter = current_node.get_current_parameter()
|
|
121
123
|
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
122
124
|
|
|
@@ -143,48 +145,6 @@ class EvaluateParameterState(State):
|
|
|
143
145
|
|
|
144
146
|
|
|
145
147
|
class ExecuteNodeState(State):
|
|
146
|
-
# TODO: https://github.com/griptape-ai/griptape-nodes/issues/864
|
|
147
|
-
@staticmethod
|
|
148
|
-
async def clear_parameter_output_values(context: ResolutionContext) -> None:
|
|
149
|
-
"""Clears all parameter output values for the currently focused node in the resolution context.
|
|
150
|
-
|
|
151
|
-
This method iterates through each parameter output value stored in the current node,
|
|
152
|
-
removes it from the node's parameter_output_values dictionary, and publishes an event
|
|
153
|
-
to notify the system about the parameter value being set to None.
|
|
154
|
-
|
|
155
|
-
Args:
|
|
156
|
-
context (ResolutionContext): The resolution context containing the focus stack
|
|
157
|
-
with the current node being processed.
|
|
158
|
-
|
|
159
|
-
Raises:
|
|
160
|
-
ValueError: If a parameter name in parameter_output_values doesn't correspond
|
|
161
|
-
to an actual parameter in the node.
|
|
162
|
-
|
|
163
|
-
Note:
|
|
164
|
-
- Uses a copy of parameter_output_values to safely modify the dictionary during iteration
|
|
165
|
-
- For each parameter, publishes a ParameterValueUpdateEvent with value=None
|
|
166
|
-
- Events are wrapped in ExecutionGriptapeNodeEvent before publishing
|
|
167
|
-
"""
|
|
168
|
-
current_node = context.focus_stack[-1].node
|
|
169
|
-
for parameter_name in current_node.parameter_output_values.copy():
|
|
170
|
-
parameter = current_node.get_parameter_by_name(parameter_name)
|
|
171
|
-
if parameter is None:
|
|
172
|
-
err = f"Attempted to execute node '{current_node.name}' but could not find parameter '{parameter_name}' that was indicated as having a value."
|
|
173
|
-
raise ValueError(err)
|
|
174
|
-
parameter_type = parameter.type
|
|
175
|
-
if parameter_type is None:
|
|
176
|
-
parameter_type = ParameterTypeBuiltin.NONE.value
|
|
177
|
-
payload = ParameterValueUpdateEvent(
|
|
178
|
-
node_name=current_node.name,
|
|
179
|
-
parameter_name=parameter_name,
|
|
180
|
-
data_type=parameter_type,
|
|
181
|
-
value=None,
|
|
182
|
-
)
|
|
183
|
-
GriptapeNodes.EventManager().put_event(
|
|
184
|
-
ExecutionGriptapeNodeEvent(wrapped_event=ExecutionEvent(payload=payload))
|
|
185
|
-
)
|
|
186
|
-
current_node.parameter_output_values.clear()
|
|
187
|
-
|
|
188
148
|
@staticmethod
|
|
189
149
|
async def collect_values_from_upstream_nodes(context: ResolutionContext) -> None:
|
|
190
150
|
"""Collect output values from resolved upstream nodes and pass them to the current node.
|
|
@@ -199,7 +159,7 @@ class ExecuteNodeState(State):
|
|
|
199
159
|
"""
|
|
200
160
|
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
201
161
|
|
|
202
|
-
current_node = context.
|
|
162
|
+
current_node = context.current_node
|
|
203
163
|
connections = GriptapeNodes.FlowManager().get_connections()
|
|
204
164
|
|
|
205
165
|
for parameter in current_node.parameters:
|
|
@@ -237,14 +197,23 @@ class ExecuteNodeState(State):
|
|
|
237
197
|
|
|
238
198
|
@staticmethod
|
|
239
199
|
async def on_enter(context: ResolutionContext) -> type[State] | None:
|
|
240
|
-
current_node = context.
|
|
200
|
+
current_node = context.current_node
|
|
241
201
|
|
|
242
202
|
# Clear all of the current output values
|
|
243
203
|
# if node is locked, don't clear anything. skip all of this.
|
|
204
|
+
GriptapeNodes.EventManager().put_event(
|
|
205
|
+
ExecutionGriptapeNodeEvent(
|
|
206
|
+
wrapped_event=ExecutionEvent(payload=CurrentDataNodeEvent(node_name=current_node.name))
|
|
207
|
+
)
|
|
208
|
+
)
|
|
244
209
|
if current_node.lock:
|
|
245
210
|
return ExecuteNodeState
|
|
246
211
|
await ExecuteNodeState.collect_values_from_upstream_nodes(context)
|
|
247
|
-
|
|
212
|
+
|
|
213
|
+
# Clear all of the current output values but don't broadcast the clearing.
|
|
214
|
+
# to avoid any flickering in subscribers (UI).
|
|
215
|
+
context.current_node.parameter_output_values.silent_clear()
|
|
216
|
+
|
|
248
217
|
for parameter in current_node.parameters:
|
|
249
218
|
if ParameterTypeBuiltin.CONTROL_TYPE.value.lower() == parameter.output_type:
|
|
250
219
|
continue
|
|
@@ -398,14 +367,17 @@ class CompleteState(State):
|
|
|
398
367
|
return None
|
|
399
368
|
|
|
400
369
|
|
|
401
|
-
class
|
|
370
|
+
class SequentialResolutionMachine(FSM[ResolutionContext]):
|
|
402
371
|
"""State machine for resolving node dependencies."""
|
|
403
372
|
|
|
404
373
|
def __init__(self) -> None:
|
|
405
374
|
resolution_context = ResolutionContext()
|
|
406
375
|
super().__init__(resolution_context)
|
|
407
376
|
|
|
408
|
-
async def resolve_node(self, node: BaseNode) -> None:
|
|
377
|
+
async def resolve_node(self, node: BaseNode | None = None) -> None:
|
|
378
|
+
if node is None:
|
|
379
|
+
msg = "SequentialResolutionMachine requires a node to resolve"
|
|
380
|
+
raise ValueError(msg)
|
|
409
381
|
self._context.focus_stack.append(Focus(node=node))
|
|
410
382
|
await self.start(InitializeSpotlightState)
|
|
411
383
|
|
|
@@ -418,6 +390,7 @@ class NodeResolutionMachine(FSM[ResolutionContext]):
|
|
|
418
390
|
def is_started(self) -> bool:
|
|
419
391
|
return self._current_state is not None
|
|
420
392
|
|
|
421
|
-
|
|
393
|
+
# Unused argument but necessary for parallel_resolution because of futures ending during cancel but not reset.
|
|
394
|
+
def reset_machine(self, *, cancel: bool = False) -> None: # noqa: ARG002
|
|
422
395
|
self._context.reset()
|
|
423
396
|
self._current_state = None
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
from typing import TYPE_CHECKING, Any, ClassVar, NamedTuple
|
|
5
5
|
|
|
6
|
-
from pydantic import BaseModel
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
7
|
|
|
8
8
|
from griptape_nodes.utils.metaclasses import SingletonMeta
|
|
9
9
|
|
|
@@ -85,6 +85,9 @@ class Setting(BaseModel):
|
|
|
85
85
|
category: str # Name of the category in the config
|
|
86
86
|
contents: dict[str, Any] # The actual settings content
|
|
87
87
|
description: str | None = None # Optional description for the setting
|
|
88
|
+
json_schema: dict[str, Any] | None = Field(
|
|
89
|
+
default=None, alias="schema"
|
|
90
|
+
) # JSON schema for the setting (including enums)
|
|
88
91
|
|
|
89
92
|
|
|
90
93
|
class LibrarySchema(BaseModel):
|
|
@@ -230,6 +233,36 @@ class LibraryRegistry(metaclass=SingletonMeta):
|
|
|
230
233
|
# Ask the library to create the node.
|
|
231
234
|
return dest_library.create_node(node_type=node_type, name=name, metadata=metadata)
|
|
232
235
|
|
|
236
|
+
@classmethod
|
|
237
|
+
def get_all_library_schemas(cls) -> dict[str, dict]:
|
|
238
|
+
"""Get schemas from all loaded libraries.
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
Dictionary mapping category names to their JSON Schema dicts
|
|
242
|
+
"""
|
|
243
|
+
instance = cls()
|
|
244
|
+
schemas = {}
|
|
245
|
+
|
|
246
|
+
# Get explicit schemas from loaded libraries
|
|
247
|
+
for library in instance._libraries.values():
|
|
248
|
+
library_data = library.get_library_data()
|
|
249
|
+
if library_data.settings:
|
|
250
|
+
for setting in library_data.settings:
|
|
251
|
+
if setting.json_schema:
|
|
252
|
+
schemas[setting.category] = {
|
|
253
|
+
"type": "object",
|
|
254
|
+
"properties": setting.json_schema,
|
|
255
|
+
"title": setting.description or f"{setting.category.title()} Settings",
|
|
256
|
+
}
|
|
257
|
+
else:
|
|
258
|
+
# Create fallback schema for settings without explicit schemas
|
|
259
|
+
schemas[setting.category] = {
|
|
260
|
+
"type": "object",
|
|
261
|
+
"title": setting.description or f"{setting.category.title()} Settings",
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return schemas
|
|
265
|
+
|
|
233
266
|
|
|
234
267
|
class Library:
|
|
235
268
|
"""A collection of nodes curated by library author.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
2
|
|
|
3
3
|
from griptape_nodes.retained_mode.events.base_events import (
|
|
4
4
|
AppPayload,
|
|
@@ -76,6 +76,10 @@ class AppGetSessionResultFailure(WorkflowNotAlteredMixin, ResultPayloadFailure):
|
|
|
76
76
|
class AppInitializationComplete(AppPayload):
|
|
77
77
|
"""Application initialization completed successfully. All subsystems ready."""
|
|
78
78
|
|
|
79
|
+
libraries_to_register: list[str] = field(default_factory=list)
|
|
80
|
+
workflows_to_register: list[str] = field(default_factory=list)
|
|
81
|
+
models_to_download: list[str] = field(default_factory=list)
|
|
82
|
+
|
|
79
83
|
|
|
80
84
|
@dataclass
|
|
81
85
|
@PayloadRegistry.register
|
|
@@ -4,7 +4,7 @@ import json
|
|
|
4
4
|
import logging
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
6
|
from dataclasses import asdict, dataclass, field, is_dataclass
|
|
7
|
-
from typing import TYPE_CHECKING, Any, ClassVar,
|
|
7
|
+
from typing import TYPE_CHECKING, Any, ClassVar, TypeVar
|
|
8
8
|
|
|
9
9
|
from griptape.artifacts import BaseArtifact
|
|
10
10
|
from griptape.mixins.serializable_mixin import SerializableMixin
|
|
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
|
|
|
20
20
|
class ResultDetail:
|
|
21
21
|
"""A single detail about an operation result, including logging level and human readable message."""
|
|
22
22
|
|
|
23
|
-
level:
|
|
23
|
+
level: int
|
|
24
24
|
message: str
|
|
25
25
|
|
|
26
26
|
|
|
@@ -34,7 +34,7 @@ class ResultDetails:
|
|
|
34
34
|
self,
|
|
35
35
|
*result_details: ResultDetail,
|
|
36
36
|
message: str | None = None,
|
|
37
|
-
level:
|
|
37
|
+
level: int | None = None,
|
|
38
38
|
logger: logging.Logger | str | None = "griptape_nodes",
|
|
39
39
|
):
|
|
40
40
|
"""Initialize with ResultDetail objects or create a single one from message/level.
|
|
@@ -67,8 +67,8 @@ class ResultDetails:
|
|
|
67
67
|
logger = logging.getLogger(logger)
|
|
68
68
|
|
|
69
69
|
for detail in self.result_details:
|
|
70
|
-
|
|
71
|
-
logger.log(
|
|
70
|
+
# Handle both string and int levels
|
|
71
|
+
logger.log(detail.level, detail.message)
|
|
72
72
|
except Exception: # noqa: S110
|
|
73
73
|
# If logging fails for any reason, don't let it break the ResultDetails creation
|
|
74
74
|
pass
|
|
@@ -135,12 +135,12 @@ class SkipTheLineMixin:
|
|
|
135
135
|
class ResultPayloadSuccess(ResultPayload, ABC):
|
|
136
136
|
"""Abstract base class for success result payloads."""
|
|
137
137
|
|
|
138
|
-
result_details: ResultDetails | str
|
|
138
|
+
result_details: ResultDetails | str
|
|
139
139
|
|
|
140
140
|
def __post_init__(self) -> None:
|
|
141
141
|
"""Initialize success result with INFO level default for strings."""
|
|
142
142
|
if isinstance(self.result_details, str):
|
|
143
|
-
self.result_details = ResultDetails(message=self.result_details, level=
|
|
143
|
+
self.result_details = ResultDetails(message=self.result_details, level=logging.DEBUG)
|
|
144
144
|
|
|
145
145
|
def succeeded(self) -> bool:
|
|
146
146
|
"""Returns True as this is a success result.
|
|
@@ -156,13 +156,13 @@ class ResultPayloadSuccess(ResultPayload, ABC):
|
|
|
156
156
|
class ResultPayloadFailure(ResultPayload, ABC):
|
|
157
157
|
"""Abstract base class for failure result payloads."""
|
|
158
158
|
|
|
159
|
-
result_details: ResultDetails | str
|
|
159
|
+
result_details: ResultDetails | str
|
|
160
160
|
exception: Exception | None = None
|
|
161
161
|
|
|
162
162
|
def __post_init__(self) -> None:
|
|
163
163
|
"""Initialize failure result with ERROR level default for strings."""
|
|
164
164
|
if isinstance(self.result_details, str):
|
|
165
|
-
self.result_details = ResultDetails(message=self.result_details, level=
|
|
165
|
+
self.result_details = ResultDetails(message=self.result_details, level=logging.ERROR)
|
|
166
166
|
|
|
167
167
|
def succeeded(self) -> bool:
|
|
168
168
|
"""Returns False as this is a failure result.
|
|
@@ -194,3 +194,33 @@ class ResetConfigResultSuccess(ResultPayloadSuccess):
|
|
|
194
194
|
@PayloadRegistry.register
|
|
195
195
|
class ResetConfigResultFailure(ResultPayloadFailure):
|
|
196
196
|
"""Configuration reset failed. Common causes: file system errors, permission issues, initialization errors."""
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@dataclass
|
|
200
|
+
@PayloadRegistry.register
|
|
201
|
+
class GetConfigSchemaRequest(RequestPayload):
|
|
202
|
+
"""Get the JSON schema for the configuration model.
|
|
203
|
+
|
|
204
|
+
Use when: Frontend needs to understand field types, enums, and validation rules
|
|
205
|
+
for rendering appropriate UI components (dropdowns, text inputs, etc.).
|
|
206
|
+
|
|
207
|
+
Results: GetConfigSchemaResultSuccess (with schema) | GetConfigSchemaResultFailure (schema generation error)
|
|
208
|
+
"""
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@dataclass
|
|
212
|
+
@PayloadRegistry.register
|
|
213
|
+
class GetConfigSchemaResultSuccess(WorkflowNotAlteredMixin, ResultPayloadSuccess):
|
|
214
|
+
"""Configuration schema retrieved successfully.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
schema: The JSON schema for the configuration model
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
schema: dict[str, Any]
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@dataclass
|
|
224
|
+
@PayloadRegistry.register
|
|
225
|
+
class GetConfigSchemaResultFailure(WorkflowNotAlteredMixin, ResultPayloadFailure):
|
|
226
|
+
"""Configuration schema retrieval failed. Common causes: schema generation error, model validation issues."""
|
|
@@ -227,8 +227,8 @@ class GetFlowStateResultSuccess(WorkflowNotAlteredMixin, ResultPayloadSuccess):
|
|
|
227
227
|
resolving_node: Name of the node currently being resolved (if any)
|
|
228
228
|
"""
|
|
229
229
|
|
|
230
|
-
|
|
231
|
-
resolving_node: str | None
|
|
230
|
+
control_nodes: list[str] | None
|
|
231
|
+
resolving_node: list[str] | None
|
|
232
232
|
|
|
233
233
|
|
|
234
234
|
@dataclass
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from griptape_nodes.retained_mode.events.base_events import (
|
|
4
|
+
RequestPayload,
|
|
5
|
+
ResultPayloadFailure,
|
|
6
|
+
ResultPayloadSuccess,
|
|
7
|
+
WorkflowNotAlteredMixin,
|
|
8
|
+
)
|
|
9
|
+
from griptape_nodes.retained_mode.events.payload_registry import PayloadRegistry
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
@PayloadRegistry.register
|
|
14
|
+
class DownloadModelRequest(RequestPayload):
|
|
15
|
+
"""Download a model from Hugging Face Hub.
|
|
16
|
+
|
|
17
|
+
Use when: Downloading models for local inference, caching models for offline use,
|
|
18
|
+
retrieving specific model versions or files from Hugging Face repositories.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
model_id: Model identifier (e.g., "microsoft/DialoGPT-medium") or full URL to Hugging Face model
|
|
22
|
+
local_dir: Optional local directory to download the model to (defaults to Hugging Face cache)
|
|
23
|
+
repo_type: Type of repository ("model", "dataset", or "space"). Defaults to "model"
|
|
24
|
+
revision: Git revision (branch, tag, or commit hash) to download. Defaults to "main"
|
|
25
|
+
allow_patterns: List of glob patterns to include when downloading. None means all files
|
|
26
|
+
ignore_patterns: List of glob patterns to exclude when downloading
|
|
27
|
+
|
|
28
|
+
Results: DownloadModelResultSuccess (with local_path) | DownloadModelResultFailure (download error)
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
model_id: str
|
|
32
|
+
local_dir: str | None = None
|
|
33
|
+
repo_type: str = "model"
|
|
34
|
+
revision: str = "main"
|
|
35
|
+
allow_patterns: list[str] | None = None
|
|
36
|
+
ignore_patterns: list[str] | None = None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
@PayloadRegistry.register
|
|
41
|
+
class DownloadModelResultSuccess(WorkflowNotAlteredMixin, ResultPayloadSuccess):
|
|
42
|
+
"""Model download completed successfully.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
model_id: The model ID that was downloaded
|
|
46
|
+
repo_info: Additional repository information returned from the download
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
model_id: str
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
@PayloadRegistry.register
|
|
54
|
+
class DownloadModelResultFailure(WorkflowNotAlteredMixin, ResultPayloadFailure):
|
|
55
|
+
"""Model download failed. Common causes: invalid model ID, network error, authentication required, storage full."""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class ModelInfo:
|
|
60
|
+
"""Information about a model."""
|
|
61
|
+
|
|
62
|
+
model_id: str
|
|
63
|
+
local_path: str | None = None
|
|
64
|
+
size_bytes: int | None = None
|
|
65
|
+
author: str | None = None
|
|
66
|
+
downloads: int | None = None
|
|
67
|
+
likes: int | None = None
|
|
68
|
+
created_at: str | None = None
|
|
69
|
+
updated_at: str | None = None
|
|
70
|
+
task: str | None = None
|
|
71
|
+
library: str | None = None
|
|
72
|
+
tags: list[str] | None = None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@dataclass
|
|
76
|
+
class QueryInfo:
|
|
77
|
+
"""Information about a search query."""
|
|
78
|
+
|
|
79
|
+
query: str | None = None
|
|
80
|
+
task: str | None = None
|
|
81
|
+
library: str | None = None
|
|
82
|
+
author: str | None = None
|
|
83
|
+
tags: list[str] | None = None
|
|
84
|
+
limit: int = 20
|
|
85
|
+
sort: str = "downloads"
|
|
86
|
+
direction: str = "desc"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@dataclass
|
|
90
|
+
@PayloadRegistry.register
|
|
91
|
+
class ListModelsRequest(RequestPayload):
|
|
92
|
+
"""List all downloaded models from the local cache.
|
|
93
|
+
|
|
94
|
+
Use when: Viewing what models are available locally, checking cache usage,
|
|
95
|
+
managing local model storage.
|
|
96
|
+
|
|
97
|
+
Results: ListModelsResultSuccess (with model list) | ListModelsResultFailure (listing error)
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@dataclass
|
|
102
|
+
@PayloadRegistry.register
|
|
103
|
+
class ListModelsResultSuccess(WorkflowNotAlteredMixin, ResultPayloadSuccess):
|
|
104
|
+
"""Model listing completed successfully.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
models: List of model information containing model_id, local_path, size_bytes, etc.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
models: list[ModelInfo]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@dataclass
|
|
114
|
+
@PayloadRegistry.register
|
|
115
|
+
class ListModelsResultFailure(WorkflowNotAlteredMixin, ResultPayloadFailure):
|
|
116
|
+
"""Model listing failed. Common causes: cache directory access error, filesystem error."""
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@dataclass
|
|
120
|
+
@PayloadRegistry.register
|
|
121
|
+
class DeleteModelRequest(RequestPayload):
|
|
122
|
+
"""Delete a downloaded model from the local cache.
|
|
123
|
+
|
|
124
|
+
Use when: Cleaning up disk space, removing unused models, managing local storage.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
model_id: Model identifier to delete from local cache
|
|
128
|
+
|
|
129
|
+
Results: DeleteModelResultSuccess (deletion confirmed) | DeleteModelResultFailure (deletion error)
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
model_id: str
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@dataclass
|
|
136
|
+
@PayloadRegistry.register
|
|
137
|
+
class DeleteModelResultSuccess(WorkflowNotAlteredMixin, ResultPayloadSuccess):
|
|
138
|
+
"""Model deletion completed successfully.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
model_id: The model ID that was deleted
|
|
142
|
+
deleted_path: Local path that was removed
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
model_id: str
|
|
146
|
+
deleted_path: str
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@dataclass
|
|
150
|
+
@PayloadRegistry.register
|
|
151
|
+
class DeleteModelResultFailure(WorkflowNotAlteredMixin, ResultPayloadFailure):
|
|
152
|
+
"""Model deletion failed. Common causes: model not found, filesystem error, permission denied."""
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@dataclass
|
|
156
|
+
@PayloadRegistry.register
|
|
157
|
+
class ListModelDownloadsRequest(RequestPayload):
|
|
158
|
+
"""List download status for a specific model or all downloads.
|
|
159
|
+
|
|
160
|
+
Use when: Checking progress of ongoing downloads, viewing download history,
|
|
161
|
+
monitoring download completion.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
model_id: Optional model identifier to get status for. If None, returns all downloads.
|
|
165
|
+
|
|
166
|
+
Results: ListModelDownloadsResultSuccess (with status data) | ListModelDownloadsResultFailure (query error)
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
model_id: str | None = None
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@dataclass
|
|
173
|
+
class ModelDownloadStatus:
|
|
174
|
+
"""Model download status tracking multiple files."""
|
|
175
|
+
|
|
176
|
+
model_id: str
|
|
177
|
+
status: str # "downloading", "completed", "failed"
|
|
178
|
+
started_at: str
|
|
179
|
+
updated_at: str
|
|
180
|
+
total_files: int | None = None
|
|
181
|
+
completed_files: int | None = None
|
|
182
|
+
failed_files: int | None = None
|
|
183
|
+
# Optional fields for completed downloads
|
|
184
|
+
completed_at: str | None = None
|
|
185
|
+
local_path: str | None = None
|
|
186
|
+
# Optional fields for failed downloads
|
|
187
|
+
failed_at: str | None = None
|
|
188
|
+
error_message: str | None = None
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@dataclass
|
|
192
|
+
@PayloadRegistry.register
|
|
193
|
+
class ListModelDownloadsResultSuccess(WorkflowNotAlteredMixin, ResultPayloadSuccess):
|
|
194
|
+
"""Model download status retrieved successfully.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
downloads: List of download status records or single status if model_id was specified
|
|
198
|
+
"""
|
|
199
|
+
|
|
200
|
+
downloads: list[ModelDownloadStatus]
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@dataclass
|
|
204
|
+
@PayloadRegistry.register
|
|
205
|
+
class ListModelDownloadsResultFailure(WorkflowNotAlteredMixin, ResultPayloadFailure):
|
|
206
|
+
"""Model download status query failed. Common causes: filesystem error, invalid model ID."""
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@dataclass
|
|
210
|
+
@PayloadRegistry.register
|
|
211
|
+
class DeleteModelDownloadRequest(RequestPayload):
|
|
212
|
+
"""Delete download status tracking records for a model.
|
|
213
|
+
|
|
214
|
+
Use when: Cleaning up orphaned download status files, removing tracking data
|
|
215
|
+
for models that are no longer needed.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
model_id: Model identifier to remove download status for
|
|
219
|
+
|
|
220
|
+
Results: DeleteModelDownloadResultSuccess (deletion confirmed) | DeleteModelDownloadResultFailure (deletion error)
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
model_id: str
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@dataclass
|
|
227
|
+
@PayloadRegistry.register
|
|
228
|
+
class DeleteModelDownloadResultSuccess(WorkflowNotAlteredMixin, ResultPayloadSuccess):
|
|
229
|
+
"""Model download status deletion completed successfully.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
model_id: The model ID whose download status was deleted
|
|
233
|
+
deleted_path: Path to the status file that was removed
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
model_id: str
|
|
237
|
+
deleted_path: str
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@dataclass
|
|
241
|
+
@PayloadRegistry.register
|
|
242
|
+
class DeleteModelDownloadResultFailure(WorkflowNotAlteredMixin, ResultPayloadFailure):
|
|
243
|
+
"""Model download status deletion failed. Common causes: status not found, filesystem error, permission denied."""
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
@dataclass
|
|
247
|
+
@PayloadRegistry.register
|
|
248
|
+
class SearchModelsRequest(RequestPayload):
|
|
249
|
+
"""Search for models on Hugging Face Hub.
|
|
250
|
+
|
|
251
|
+
Use when: Finding models by name, filtering models by task or library,
|
|
252
|
+
discovering available models for specific use cases.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
query: Search query string to match against model names and descriptions
|
|
256
|
+
task: Filter by task type (e.g., "text-generation", "image-classification")
|
|
257
|
+
library: Filter by library (e.g., "transformers", "diffusers", "timm")
|
|
258
|
+
author: Filter by author/organization name
|
|
259
|
+
tags: List of tags to filter by
|
|
260
|
+
limit: Maximum number of results to return (default: 20, max: 100)
|
|
261
|
+
sort: Sort results by "downloads", "likes", "updated", or "created" (default: "downloads")
|
|
262
|
+
direction: Sort direction "asc" or "desc" (default: "desc")
|
|
263
|
+
|
|
264
|
+
Results: SearchModelsResultSuccess (with model list) | SearchModelsResultFailure (search error)
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
query: str | None = None
|
|
268
|
+
task: str | None = None
|
|
269
|
+
library: str | None = None
|
|
270
|
+
author: str | None = None
|
|
271
|
+
tags: list[str] | None = None
|
|
272
|
+
limit: int = 20
|
|
273
|
+
sort: str = "downloads"
|
|
274
|
+
direction: str = "desc"
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
@dataclass
|
|
278
|
+
@PayloadRegistry.register
|
|
279
|
+
class SearchModelsResultSuccess(WorkflowNotAlteredMixin, ResultPayloadSuccess):
|
|
280
|
+
"""Model search completed successfully.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
models: List of model information containing id, author, downloads, etc.
|
|
284
|
+
total_results: Total number of models matching the search criteria
|
|
285
|
+
query_info: Information about the search query parameters used
|
|
286
|
+
"""
|
|
287
|
+
|
|
288
|
+
models: list[ModelInfo]
|
|
289
|
+
total_results: int
|
|
290
|
+
query_info: QueryInfo
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
@dataclass
|
|
294
|
+
@PayloadRegistry.register
|
|
295
|
+
class SearchModelsResultFailure(WorkflowNotAlteredMixin, ResultPayloadFailure):
|
|
296
|
+
"""Model search failed. Common causes: network error, invalid parameters, API limits."""
|
|
@@ -3,6 +3,7 @@ from enum import Enum, auto
|
|
|
3
3
|
from typing import Any, NamedTuple, NewType
|
|
4
4
|
from uuid import uuid4
|
|
5
5
|
|
|
6
|
+
from griptape_nodes.exe_types.core_types import NodeMessagePayload
|
|
6
7
|
from griptape_nodes.exe_types.node_types import NodeResolutionState
|
|
7
8
|
from griptape_nodes.node_library.library_registry import LibraryNameAndVersion
|
|
8
9
|
from griptape_nodes.retained_mode.events.base_events import (
|
|
@@ -744,7 +745,7 @@ class SendNodeMessageRequest(RequestPayload):
|
|
|
744
745
|
"""
|
|
745
746
|
|
|
746
747
|
message_type: str
|
|
747
|
-
message:
|
|
748
|
+
message: NodeMessagePayload | None
|
|
748
749
|
node_name: str | None = None
|
|
749
750
|
optional_element_name: str | None = None
|
|
750
751
|
|
|
@@ -758,7 +759,7 @@ class SendNodeMessageResultSuccess(ResultPayloadSuccess):
|
|
|
758
759
|
response: Optional response data from the node's message handler
|
|
759
760
|
"""
|
|
760
761
|
|
|
761
|
-
response:
|
|
762
|
+
response: NodeMessagePayload | None = None
|
|
762
763
|
|
|
763
764
|
|
|
764
765
|
@dataclass
|
|
@@ -773,7 +774,7 @@ class SendNodeMessageResultFailure(ResultPayloadFailure):
|
|
|
773
774
|
response: Optional response data from the node's message handler (even on failure)
|
|
774
775
|
"""
|
|
775
776
|
|
|
776
|
-
response:
|
|
777
|
+
response: NodeMessagePayload | None = None
|
|
777
778
|
|
|
778
779
|
|
|
779
780
|
@dataclass
|