griptape-nodes 0.64.11__py3-none-any.whl → 0.65.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- griptape_nodes/app/app.py +25 -5
- griptape_nodes/cli/commands/init.py +65 -54
- griptape_nodes/cli/commands/libraries.py +92 -85
- griptape_nodes/cli/commands/self.py +121 -0
- griptape_nodes/common/node_executor.py +2142 -101
- griptape_nodes/exe_types/base_iterative_nodes.py +1004 -0
- griptape_nodes/exe_types/connections.py +114 -19
- griptape_nodes/exe_types/core_types.py +225 -7
- griptape_nodes/exe_types/flow.py +3 -3
- griptape_nodes/exe_types/node_types.py +681 -225
- griptape_nodes/exe_types/param_components/README.md +414 -0
- griptape_nodes/exe_types/param_components/api_key_provider_parameter.py +200 -0
- griptape_nodes/exe_types/param_components/huggingface/huggingface_model_parameter.py +2 -0
- griptape_nodes/exe_types/param_components/huggingface/huggingface_repo_file_parameter.py +79 -5
- griptape_nodes/exe_types/param_types/parameter_button.py +443 -0
- griptape_nodes/machines/control_flow.py +84 -38
- griptape_nodes/machines/dag_builder.py +148 -70
- griptape_nodes/machines/parallel_resolution.py +61 -35
- griptape_nodes/machines/sequential_resolution.py +11 -113
- griptape_nodes/retained_mode/events/app_events.py +1 -0
- griptape_nodes/retained_mode/events/base_events.py +16 -13
- griptape_nodes/retained_mode/events/connection_events.py +3 -0
- griptape_nodes/retained_mode/events/execution_events.py +35 -0
- griptape_nodes/retained_mode/events/flow_events.py +15 -2
- griptape_nodes/retained_mode/events/library_events.py +347 -0
- griptape_nodes/retained_mode/events/node_events.py +48 -0
- griptape_nodes/retained_mode/events/os_events.py +86 -3
- griptape_nodes/retained_mode/events/project_events.py +15 -1
- griptape_nodes/retained_mode/events/workflow_events.py +48 -1
- griptape_nodes/retained_mode/griptape_nodes.py +6 -2
- griptape_nodes/retained_mode/managers/config_manager.py +10 -8
- griptape_nodes/retained_mode/managers/event_manager.py +168 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/__init__.py +2 -0
- griptape_nodes/retained_mode/managers/fitness_problems/libraries/old_xdg_location_warning_problem.py +43 -0
- griptape_nodes/retained_mode/managers/flow_manager.py +664 -123
- griptape_nodes/retained_mode/managers/library_manager.py +1142 -138
- griptape_nodes/retained_mode/managers/model_manager.py +2 -3
- griptape_nodes/retained_mode/managers/node_manager.py +148 -25
- griptape_nodes/retained_mode/managers/object_manager.py +3 -1
- griptape_nodes/retained_mode/managers/operation_manager.py +3 -1
- griptape_nodes/retained_mode/managers/os_manager.py +1158 -122
- griptape_nodes/retained_mode/managers/secrets_manager.py +2 -3
- griptape_nodes/retained_mode/managers/settings.py +21 -1
- griptape_nodes/retained_mode/managers/sync_manager.py +2 -3
- griptape_nodes/retained_mode/managers/workflow_manager.py +358 -104
- griptape_nodes/retained_mode/retained_mode.py +3 -3
- griptape_nodes/traits/button.py +44 -2
- griptape_nodes/traits/file_system_picker.py +2 -2
- griptape_nodes/utils/file_utils.py +101 -0
- griptape_nodes/utils/git_utils.py +1236 -0
- griptape_nodes/utils/library_utils.py +122 -0
- {griptape_nodes-0.64.11.dist-info → griptape_nodes-0.65.1.dist-info}/METADATA +2 -1
- {griptape_nodes-0.64.11.dist-info → griptape_nodes-0.65.1.dist-info}/RECORD +55 -47
- {griptape_nodes-0.64.11.dist-info → griptape_nodes-0.65.1.dist-info}/WHEEL +1 -1
- {griptape_nodes-0.64.11.dist-info → griptape_nodes-0.65.1.dist-info}/entry_points.txt +0 -0
griptape_nodes/app/app.py
CHANGED
|
@@ -73,6 +73,8 @@ websocket_event_loop_ready = threading.Event()
|
|
|
73
73
|
# Semaphore to limit concurrent requests
|
|
74
74
|
REQUEST_SEMAPHORE = asyncio.Semaphore(100)
|
|
75
75
|
|
|
76
|
+
config_manager = GriptapeNodes.ConfigManager()
|
|
77
|
+
|
|
76
78
|
|
|
77
79
|
class EventLogHandler(logging.Handler):
|
|
78
80
|
"""Custom logging handler that emits log messages as AppEvents.
|
|
@@ -81,18 +83,24 @@ class EventLogHandler(logging.Handler):
|
|
|
81
83
|
"""
|
|
82
84
|
|
|
83
85
|
def emit(self, record: logging.LogRecord) -> None:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
log_level_no = logging.getLevelNamesMapping()[config_manager.get_config_value("log_level").upper()]
|
|
87
|
+
if record.levelno >= log_level_no:
|
|
88
|
+
log_event = AppEvent(
|
|
89
|
+
payload=LogHandlerEvent(message=record.getMessage(), levelname=record.levelname, created=record.created)
|
|
90
|
+
)
|
|
91
|
+
griptape_nodes.EventManager().put_event(log_event)
|
|
88
92
|
|
|
89
93
|
|
|
90
94
|
# Logger for this module. Important that this is not the same as the griptape_nodes logger or else we'll have infinite log events.
|
|
91
95
|
logger = logging.getLogger("griptape_nodes_app")
|
|
92
96
|
|
|
97
|
+
# Get configured log level from config
|
|
98
|
+
log_level_str = config_manager.get_config_value("log_level").upper()
|
|
99
|
+
log_level = logging.getLevelNamesMapping()[log_level_str]
|
|
100
|
+
|
|
93
101
|
griptape_nodes_logger = logging.getLogger("griptape_nodes")
|
|
94
102
|
griptape_nodes_logger.addHandler(EventLogHandler())
|
|
95
|
-
griptape_nodes_logger.setLevel(
|
|
103
|
+
griptape_nodes_logger.setLevel(log_level)
|
|
96
104
|
|
|
97
105
|
# Root logger only gets RichHandler for console output
|
|
98
106
|
logging.basicConfig(
|
|
@@ -313,6 +321,10 @@ async def _process_app_event(event: AppEvent) -> None:
|
|
|
313
321
|
|
|
314
322
|
async def _process_node_event(event: GriptapeNodeEvent) -> None:
|
|
315
323
|
"""Process GriptapeNodeEvents and send them to the API (async version)."""
|
|
324
|
+
# Check if events are suppressed
|
|
325
|
+
if griptape_nodes.EventManager().should_suppress_event(event):
|
|
326
|
+
return
|
|
327
|
+
|
|
316
328
|
# Emit the result back to the GUI
|
|
317
329
|
result_event = event.wrapped_event
|
|
318
330
|
|
|
@@ -341,11 +353,19 @@ async def _process_node_event(event: GriptapeNodeEvent) -> None:
|
|
|
341
353
|
|
|
342
354
|
async def _process_execution_node_event(event: ExecutionGriptapeNodeEvent) -> None:
|
|
343
355
|
"""Process ExecutionGriptapeNodeEvents and send them to the API (async version)."""
|
|
356
|
+
# Check if events are suppressed
|
|
357
|
+
if griptape_nodes.EventManager().should_suppress_event(event):
|
|
358
|
+
return
|
|
359
|
+
|
|
344
360
|
await _send_message("execution_event", event.wrapped_event.json())
|
|
345
361
|
|
|
346
362
|
|
|
347
363
|
async def _process_progress_event(gt_event: ProgressEvent) -> None:
|
|
348
364
|
"""Process Griptape framework events and send them to the API (async version)."""
|
|
365
|
+
# Check if events are suppressed
|
|
366
|
+
if griptape_nodes.EventManager().should_suppress_event(gt_event):
|
|
367
|
+
return
|
|
368
|
+
|
|
349
369
|
node_name = gt_event.node_name
|
|
350
370
|
if node_name:
|
|
351
371
|
value = gt_event.value
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"""Init command for Griptape Nodes CLI."""
|
|
2
2
|
|
|
3
|
-
import asyncio
|
|
4
3
|
import json
|
|
5
4
|
from pathlib import Path
|
|
6
|
-
from typing import Annotated, Any
|
|
5
|
+
from typing import Annotated, Any, NamedTuple
|
|
7
6
|
|
|
8
7
|
import typer
|
|
9
8
|
from rich.box import HEAVY_EDGE
|
|
@@ -11,12 +10,10 @@ from rich.panel import Panel
|
|
|
11
10
|
from rich.prompt import Confirm, Prompt
|
|
12
11
|
from rich.table import Table
|
|
13
12
|
|
|
14
|
-
from griptape_nodes.cli.commands.libraries import _sync_libraries
|
|
15
13
|
from griptape_nodes.cli.shared import (
|
|
16
14
|
CONFIG_DIR,
|
|
17
15
|
CONFIG_FILE,
|
|
18
16
|
ENV_FILE,
|
|
19
|
-
ENV_LIBRARIES_BASE_DIR,
|
|
20
17
|
GT_CLOUD_BASE_URL,
|
|
21
18
|
NODES_APP_URL,
|
|
22
19
|
InitConfig,
|
|
@@ -25,6 +22,9 @@ from griptape_nodes.cli.shared import (
|
|
|
25
22
|
from griptape_nodes.drivers.storage import StorageBackend
|
|
26
23
|
from griptape_nodes.drivers.storage.griptape_cloud_storage_driver import GriptapeCloudStorageDriver
|
|
27
24
|
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
25
|
+
from griptape_nodes.retained_mode.managers.settings import LIBRARIES_TO_DOWNLOAD_KEY, LIBRARIES_TO_REGISTER_KEY
|
|
26
|
+
from griptape_nodes.utils.git_utils import extract_repo_name_from_url
|
|
27
|
+
from griptape_nodes.utils.library_utils import filter_old_xdg_library_paths
|
|
28
28
|
|
|
29
29
|
config_manager = GriptapeNodes.ConfigManager()
|
|
30
30
|
secrets_manager = GriptapeNodes.SecretsManager()
|
|
@@ -54,10 +54,6 @@ def init_command( # noqa: PLR0913
|
|
|
54
54
|
help="Install the Griptape Cloud Library.",
|
|
55
55
|
),
|
|
56
56
|
] = None,
|
|
57
|
-
libraries_sync: Annotated[
|
|
58
|
-
bool | None,
|
|
59
|
-
typer.Option("--libraries-sync/--no-libraries-sync", help="Sync the Griptape Nodes libraries."),
|
|
60
|
-
] = None,
|
|
61
57
|
no_interactive: Annotated[ # noqa: FBT002
|
|
62
58
|
bool,
|
|
63
59
|
typer.Option(help="Run init in non-interactive mode (no prompts)."),
|
|
@@ -93,7 +89,6 @@ def init_command( # noqa: PLR0913
|
|
|
93
89
|
register_griptape_cloud_library=register_griptape_cloud_library,
|
|
94
90
|
config_values=config_values,
|
|
95
91
|
secret_values=secret_values,
|
|
96
|
-
libraries_sync=libraries_sync,
|
|
97
92
|
bucket_name=bucket_name,
|
|
98
93
|
hf_token=hf_token,
|
|
99
94
|
)
|
|
@@ -111,10 +106,6 @@ def _run_init(config: InitConfig) -> None:
|
|
|
111
106
|
# Run configuration flow
|
|
112
107
|
_run_init_configuration(config)
|
|
113
108
|
|
|
114
|
-
# Sync libraries
|
|
115
|
-
if config.libraries_sync is not False:
|
|
116
|
-
asyncio.run(_sync_libraries(load_libraries_from_config=False))
|
|
117
|
-
|
|
118
109
|
console.print("[bold green]Initialization complete![/bold green]")
|
|
119
110
|
|
|
120
111
|
|
|
@@ -240,14 +231,24 @@ def _handle_additional_library_config(config: InitConfig) -> bool | None:
|
|
|
240
231
|
)
|
|
241
232
|
|
|
242
233
|
if register_advanced_library is not None or register_griptape_cloud_library is not None:
|
|
243
|
-
|
|
234
|
+
libraries_config = _build_libraries_list(
|
|
244
235
|
register_advanced_library=register_advanced_library,
|
|
245
236
|
register_griptape_cloud_library=register_griptape_cloud_library,
|
|
246
237
|
)
|
|
247
238
|
config_manager.set_config_value(
|
|
248
|
-
|
|
239
|
+
LIBRARIES_TO_DOWNLOAD_KEY,
|
|
240
|
+
libraries_config.libraries_to_download,
|
|
241
|
+
)
|
|
242
|
+
config_manager.set_config_value(
|
|
243
|
+
LIBRARIES_TO_REGISTER_KEY,
|
|
244
|
+
libraries_config.libraries_to_register,
|
|
245
|
+
)
|
|
246
|
+
console.print(
|
|
247
|
+
f"[bold green]Libraries to download: {', '.join(libraries_config.libraries_to_download)}[/bold green]"
|
|
248
|
+
)
|
|
249
|
+
console.print(
|
|
250
|
+
f"[bold green]Libraries to register: {', '.join(libraries_config.libraries_to_register)}[/bold green]"
|
|
249
251
|
)
|
|
250
|
-
console.print(f"[bold green]Libraries to register set to: {', '.join(libraries_to_register)}[/bold green]")
|
|
251
252
|
|
|
252
253
|
return register_advanced_library
|
|
253
254
|
|
|
@@ -500,62 +501,72 @@ def _prompt_for_griptape_cloud_library(*, default_prompt_for_griptape_cloud_libr
|
|
|
500
501
|
return Confirm.ask("Register Griptape Cloud Library?", default=default_prompt_for_griptape_cloud_library)
|
|
501
502
|
|
|
502
503
|
|
|
504
|
+
class LibrariesConfig(NamedTuple):
|
|
505
|
+
"""Configuration for library lists."""
|
|
506
|
+
|
|
507
|
+
libraries_to_download: list[str]
|
|
508
|
+
libraries_to_register: list[str]
|
|
509
|
+
|
|
510
|
+
|
|
503
511
|
def _build_libraries_list(
|
|
504
512
|
*, register_advanced_library: bool | None = False, register_griptape_cloud_library: bool | None = False
|
|
505
|
-
) ->
|
|
506
|
-
"""Builds the
|
|
507
|
-
#
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
+
) -> LibrariesConfig:
|
|
514
|
+
"""Builds the lists of libraries to download and register based on library settings."""
|
|
515
|
+
# Get current configuration for both lists
|
|
516
|
+
download_key = LIBRARIES_TO_DOWNLOAD_KEY
|
|
517
|
+
register_key = LIBRARIES_TO_REGISTER_KEY
|
|
518
|
+
|
|
519
|
+
current_downloads = config_manager.get_config_value(
|
|
520
|
+
download_key,
|
|
513
521
|
config_source="user_config",
|
|
514
|
-
default=config_manager.get_config_value(
|
|
522
|
+
default=config_manager.get_config_value(download_key, config_source="default_config", default=[]),
|
|
515
523
|
)
|
|
516
|
-
|
|
524
|
+
current_register = config_manager.get_config_value(
|
|
525
|
+
register_key,
|
|
526
|
+
config_source="user_config",
|
|
527
|
+
default=config_manager.get_config_value(register_key, config_source="default_config", default=[]),
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
new_downloads = current_downloads.copy()
|
|
531
|
+
new_register = current_register.copy()
|
|
517
532
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
path = Path(library_path)
|
|
521
|
-
return f"{path.parent.name}/{path.name}"
|
|
533
|
+
# Remove old XDG data home library paths from libraries_to_register
|
|
534
|
+
new_register, _ = filter_old_xdg_library_paths(new_register)
|
|
522
535
|
|
|
523
|
-
# Create a set of current
|
|
524
|
-
|
|
536
|
+
# Create a set of current download identifiers for fast lookup
|
|
537
|
+
current_download_identifiers = {extract_repo_name_from_url(lib) for lib in current_downloads}
|
|
525
538
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
if default_identifier not in
|
|
530
|
-
|
|
539
|
+
# Default library
|
|
540
|
+
default_library = "https://github.com/griptape-ai/griptape-nodes-library-standard@stable"
|
|
541
|
+
default_identifier = extract_repo_name_from_url(default_library)
|
|
542
|
+
if default_identifier not in current_download_identifiers:
|
|
543
|
+
new_downloads.append(default_library)
|
|
531
544
|
|
|
532
|
-
|
|
533
|
-
|
|
545
|
+
# Advanced media library
|
|
546
|
+
advanced_media_library = "https://github.com/griptape-ai/griptape-nodes-library-advanced-media@stable"
|
|
547
|
+
advanced_identifier = extract_repo_name_from_url(advanced_media_library)
|
|
534
548
|
if register_advanced_library:
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
new_libraries.append(advanced_media_library)
|
|
549
|
+
if advanced_identifier not in current_download_identifiers:
|
|
550
|
+
new_downloads.append(advanced_media_library)
|
|
538
551
|
else:
|
|
539
|
-
|
|
540
|
-
libraries_to_remove = [lib for lib in new_libraries if _get_library_identifier(lib) == advanced_identifier]
|
|
552
|
+
libraries_to_remove = [lib for lib in new_downloads if extract_repo_name_from_url(lib) == advanced_identifier]
|
|
541
553
|
for lib in libraries_to_remove:
|
|
542
|
-
|
|
554
|
+
new_downloads.remove(lib)
|
|
543
555
|
|
|
544
|
-
|
|
545
|
-
|
|
556
|
+
# Griptape Cloud library
|
|
557
|
+
griptape_cloud_library = "https://github.com/griptape-ai/griptape-nodes-library-griptape-cloud@stable"
|
|
558
|
+
griptape_cloud_identifier = extract_repo_name_from_url(griptape_cloud_library)
|
|
546
559
|
if register_griptape_cloud_library:
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
new_libraries.append(griptape_cloud_library)
|
|
560
|
+
if griptape_cloud_identifier not in current_download_identifiers:
|
|
561
|
+
new_downloads.append(griptape_cloud_library)
|
|
550
562
|
else:
|
|
551
|
-
# If the griptape cloud library is registered, remove it
|
|
552
563
|
libraries_to_remove = [
|
|
553
|
-
lib for lib in
|
|
564
|
+
lib for lib in new_downloads if extract_repo_name_from_url(lib) == griptape_cloud_identifier
|
|
554
565
|
]
|
|
555
566
|
for lib in libraries_to_remove:
|
|
556
|
-
|
|
567
|
+
new_downloads.remove(lib)
|
|
557
568
|
|
|
558
|
-
return
|
|
569
|
+
return LibrariesConfig(libraries_to_download=new_downloads, libraries_to_register=new_register)
|
|
559
570
|
|
|
560
571
|
|
|
561
572
|
def _create_new_bucket(bucket_name: str) -> str:
|
|
@@ -1,101 +1,108 @@
|
|
|
1
1
|
"""Libraries command for Griptape Nodes CLI."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
import shutil
|
|
5
|
-
import tarfile
|
|
6
|
-
import tempfile
|
|
7
|
-
from pathlib import Path
|
|
8
4
|
|
|
9
|
-
import httpx
|
|
10
5
|
import typer
|
|
11
|
-
from rich.progress import Progress
|
|
12
6
|
|
|
13
|
-
from griptape_nodes.cli.shared import
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
from griptape_nodes.cli.shared import console
|
|
8
|
+
from griptape_nodes.retained_mode.events.library_events import (
|
|
9
|
+
DownloadLibraryRequest,
|
|
10
|
+
DownloadLibraryResultSuccess,
|
|
11
|
+
SyncLibrariesRequest,
|
|
12
|
+
SyncLibrariesResultSuccess,
|
|
18
13
|
)
|
|
19
|
-
from griptape_nodes.retained_mode.events.os_events import DeleteFileRequest, DeleteFileResultSuccess
|
|
20
14
|
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
21
|
-
from griptape_nodes.utils.
|
|
15
|
+
from griptape_nodes.utils.git_utils import normalize_github_url
|
|
22
16
|
|
|
23
17
|
app = typer.Typer(help="Manage local libraries.")
|
|
24
18
|
|
|
25
19
|
|
|
26
20
|
@app.command()
|
|
27
|
-
def sync(
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
def sync(
|
|
22
|
+
overwrite: bool = typer.Option(False, "--overwrite", help="Discard uncommitted changes in libraries"), # noqa: FBT001
|
|
23
|
+
) -> None:
|
|
24
|
+
"""Sync all libraries to latest versions from their git repositories."""
|
|
25
|
+
asyncio.run(_sync_libraries(overwrite_existing=overwrite))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async def _sync_libraries(*, overwrite_existing: bool) -> None:
|
|
29
|
+
"""Sync all libraries by checking for updates and installing dependencies."""
|
|
30
|
+
console.print("[bold cyan]Syncing libraries...[/bold cyan]")
|
|
31
|
+
|
|
32
|
+
# Create sync request with provided parameters
|
|
33
|
+
request = SyncLibrariesRequest(
|
|
34
|
+
overwrite_existing=overwrite_existing,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Execute the sync
|
|
38
|
+
result = await GriptapeNodes.ahandle_request(request)
|
|
39
|
+
|
|
40
|
+
# Display results - failure case first
|
|
41
|
+
if not isinstance(result, SyncLibrariesResultSuccess):
|
|
42
|
+
console.print(f"[red]Failed to sync libraries: {result.result_details}[/red]")
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
# Success path
|
|
46
|
+
console.print(f"[green]Checked {result.libraries_checked} libraries[/green]")
|
|
47
|
+
|
|
48
|
+
if result.libraries_updated > 0:
|
|
49
|
+
console.print(f"[bold green]Updated {result.libraries_updated} libraries:[/bold green]")
|
|
50
|
+
for lib_name, update_info in result.update_summary.items():
|
|
51
|
+
if update_info.get("status") == "updated":
|
|
52
|
+
console.print(
|
|
53
|
+
f" [green]✓ {lib_name}: {update_info['old_version']} → {update_info['new_version']}[/green]"
|
|
54
|
+
)
|
|
55
|
+
elif update_info.get("status") == "failed":
|
|
56
|
+
console.print(f" [red]✗ {lib_name}: {update_info.get('error', 'Unknown error')}[/red]")
|
|
57
|
+
else:
|
|
58
|
+
console.print("[green]All libraries are up to date[/green]")
|
|
31
59
|
|
|
32
|
-
|
|
33
|
-
"""Download and sync Griptape Nodes libraries, copying only directories from synced libraries.
|
|
60
|
+
console.print("[bold green]Libraries synced successfully.[/bold green]")
|
|
34
61
|
|
|
35
|
-
Args:
|
|
36
|
-
load_libraries_from_config (bool): If True, re-initialize all libraries from config
|
|
37
62
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
console.print(f"[
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
# Use DeleteFileRequest for centralized deletion with Windows compatibility
|
|
85
|
-
request = DeleteFileRequest(path=str(dest_library_dir), workspace_only=False)
|
|
86
|
-
result = await GriptapeNodes.OSManager().on_delete_file_request(request)
|
|
87
|
-
if not isinstance(result, DeleteFileResultSuccess):
|
|
88
|
-
console.print(f"[yellow]Warning: Failed to delete existing library {library_dir.name}[/yellow]")
|
|
89
|
-
shutil.copytree(library_dir, dest_library_dir)
|
|
90
|
-
console.print(f"[green]Synced library: {library_dir.name}[/green]")
|
|
91
|
-
|
|
92
|
-
# Re-initialize all libraries from config
|
|
93
|
-
if load_libraries_from_config:
|
|
94
|
-
console.print("[bold cyan]Initializing libraries...[/bold cyan]")
|
|
95
|
-
try:
|
|
96
|
-
await GriptapeNodes.LibraryManager().load_all_libraries_from_config()
|
|
97
|
-
console.print("[bold green]Libraries Initialized successfully.[/bold green]")
|
|
98
|
-
except Exception as e:
|
|
99
|
-
console.print(f"[red]Error initializing libraries: {e}[/red]")
|
|
100
|
-
|
|
101
|
-
console.print("[bold green]Libraries synced.[/bold green]")
|
|
63
|
+
@app.command()
|
|
64
|
+
def download(
|
|
65
|
+
git_url: str = typer.Argument(..., help="Git repository URL to download"),
|
|
66
|
+
branch: str | None = typer.Option(None, "--branch", help="Branch, tag, or commit to checkout"),
|
|
67
|
+
target_dir: str | None = typer.Option(None, "--target-dir", help="Target directory name"),
|
|
68
|
+
download_dir: str | None = typer.Option(None, "--download-dir", help="Parent directory for library download"),
|
|
69
|
+
overwrite: bool = typer.Option(False, "--overwrite", help="Overwrite existing library directory if it exists"), # noqa: FBT001
|
|
70
|
+
) -> None:
|
|
71
|
+
"""Download a library from a git repository."""
|
|
72
|
+
asyncio.run(_download_library(git_url, branch, target_dir, download_dir, overwrite_existing=overwrite))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
async def _download_library(
|
|
76
|
+
git_url: str,
|
|
77
|
+
branch_tag_commit: str | None,
|
|
78
|
+
target_directory_name: str | None,
|
|
79
|
+
download_directory: str | None,
|
|
80
|
+
*,
|
|
81
|
+
overwrite_existing: bool,
|
|
82
|
+
) -> None:
|
|
83
|
+
"""Download a library from a git repository."""
|
|
84
|
+
# Normalize GitHub shorthand to full URL
|
|
85
|
+
git_url = normalize_github_url(git_url)
|
|
86
|
+
|
|
87
|
+
console.print(f"[bold cyan]Downloading library from {git_url}...[/bold cyan]")
|
|
88
|
+
|
|
89
|
+
# Create the download request
|
|
90
|
+
request = DownloadLibraryRequest(
|
|
91
|
+
git_url=git_url,
|
|
92
|
+
branch_tag_commit=branch_tag_commit,
|
|
93
|
+
target_directory_name=target_directory_name,
|
|
94
|
+
download_directory=download_directory,
|
|
95
|
+
overwrite_existing=overwrite_existing,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# Execute the download
|
|
99
|
+
result = await GriptapeNodes.ahandle_request(request)
|
|
100
|
+
|
|
101
|
+
# Display results - failure case first
|
|
102
|
+
if not isinstance(result, DownloadLibraryResultSuccess):
|
|
103
|
+
console.print(f"[red]Failed to download library: {result.result_details}[/red]")
|
|
104
|
+
return
|
|
105
|
+
|
|
106
|
+
# Success path
|
|
107
|
+
console.print(f"[bold green]Library '{result.library_name}' downloaded successfully![/bold green]")
|
|
108
|
+
console.print(f"[green]Downloaded to: {result.library_path}[/green]")
|
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
"""Self command for Griptape Nodes CLI."""
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
4
|
+
import json
|
|
5
|
+
import platform
|
|
3
6
|
import shutil
|
|
4
7
|
import sys
|
|
5
8
|
|
|
6
9
|
import typer
|
|
10
|
+
from rich.table import Table
|
|
7
11
|
|
|
8
12
|
from griptape_nodes.cli.shared import (
|
|
9
13
|
CONFIG_DIR,
|
|
14
|
+
CONFIG_FILE,
|
|
10
15
|
DATA_DIR,
|
|
11
16
|
GITHUB_UPDATE_URL,
|
|
12
17
|
LATEST_TAG,
|
|
13
18
|
PYPI_UPDATE_URL,
|
|
14
19
|
console,
|
|
15
20
|
)
|
|
21
|
+
from griptape_nodes.node_library.library_registry import LibraryRegistry
|
|
22
|
+
from griptape_nodes.retained_mode.events.library_events import LoadLibrariesRequest
|
|
16
23
|
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
17
24
|
from griptape_nodes.utils.uv_utils import find_uv_bin
|
|
18
25
|
from griptape_nodes.utils.version_utils import (
|
|
19
26
|
get_complete_version_string,
|
|
20
27
|
get_current_version,
|
|
28
|
+
get_install_source,
|
|
21
29
|
get_latest_version_git,
|
|
22
30
|
get_latest_version_pypi,
|
|
23
31
|
)
|
|
@@ -47,6 +55,12 @@ def version() -> None:
|
|
|
47
55
|
_print_current_version()
|
|
48
56
|
|
|
49
57
|
|
|
58
|
+
@app.command()
|
|
59
|
+
def info() -> None:
|
|
60
|
+
"""Display system information for debugging."""
|
|
61
|
+
asyncio.run(_print_system_info_async())
|
|
62
|
+
|
|
63
|
+
|
|
50
64
|
def _get_latest_version(package: str, install_source: str) -> str:
|
|
51
65
|
"""Fetches the latest release tag from PyPI.
|
|
52
66
|
|
|
@@ -118,3 +132,110 @@ def _uninstall_self() -> None:
|
|
|
118
132
|
# Remove the tool using UV
|
|
119
133
|
uv_path = find_uv_bin()
|
|
120
134
|
os_manager.replace_process([uv_path, "tool", "uninstall", "griptape-nodes"])
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
async def _print_system_info_async() -> None:
|
|
138
|
+
"""Print comprehensive system information (async wrapper to load libraries)."""
|
|
139
|
+
# Load libraries from configuration first
|
|
140
|
+
load_request = LoadLibrariesRequest()
|
|
141
|
+
await GriptapeNodes.ahandle_request(load_request)
|
|
142
|
+
|
|
143
|
+
# Now print all the info
|
|
144
|
+
_print_system_info()
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _print_system_info() -> None:
|
|
148
|
+
"""Print comprehensive system information."""
|
|
149
|
+
console.print("\n[bold cyan]Griptape Nodes System Information[/bold cyan]\n")
|
|
150
|
+
|
|
151
|
+
_print_engine_info()
|
|
152
|
+
_print_platform_info()
|
|
153
|
+
_print_paths_info()
|
|
154
|
+
_print_configuration()
|
|
155
|
+
_print_registered_libraries()
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _print_engine_info() -> None:
|
|
159
|
+
"""Print engine version information."""
|
|
160
|
+
version_string = get_complete_version_string()
|
|
161
|
+
install_source, commit_id = get_install_source()
|
|
162
|
+
|
|
163
|
+
console.print("[bold]Engine:[/bold]")
|
|
164
|
+
console.print(f" Version: {version_string}")
|
|
165
|
+
console.print(f" Install Source: {install_source}")
|
|
166
|
+
if commit_id:
|
|
167
|
+
console.print(f" Commit ID: {commit_id}")
|
|
168
|
+
console.print()
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _print_platform_info() -> None:
|
|
172
|
+
"""Print platform information."""
|
|
173
|
+
console.print("[bold]Platform:[/bold]")
|
|
174
|
+
console.print(f" OS: {platform.system()}")
|
|
175
|
+
console.print(f" OS Version: {platform.version()}")
|
|
176
|
+
console.print(f" OS Release: {platform.release()}")
|
|
177
|
+
console.print(f" Architecture: {platform.machine()}")
|
|
178
|
+
console.print(f" Python Version: {platform.python_version()}")
|
|
179
|
+
console.print(f" Python Implementation: {platform.python_implementation()}")
|
|
180
|
+
console.print(f" Python Executable: {sys.executable}")
|
|
181
|
+
console.print()
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _print_paths_info() -> None:
|
|
185
|
+
"""Print configuration paths."""
|
|
186
|
+
console.print("[bold]Paths:[/bold]")
|
|
187
|
+
console.print(f" Config Directory: {CONFIG_DIR}")
|
|
188
|
+
console.print(f" Config File: {CONFIG_FILE}")
|
|
189
|
+
console.print(f" Data Directory: {DATA_DIR}")
|
|
190
|
+
|
|
191
|
+
workspace_dir = config_manager.get_config_value("file_system.directories.workspace_directory")
|
|
192
|
+
if workspace_dir:
|
|
193
|
+
console.print(f" Workspace Directory: {workspace_dir}")
|
|
194
|
+
console.print()
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _print_configuration() -> None:
|
|
198
|
+
"""Print full configuration."""
|
|
199
|
+
console.print("[bold]Configuration:[/bold]")
|
|
200
|
+
try:
|
|
201
|
+
full_config = config_manager.merged_config
|
|
202
|
+
config_json = json.dumps(full_config, indent=2, default=str)
|
|
203
|
+
console.print(f"[dim]{config_json}[/dim]")
|
|
204
|
+
except Exception as e:
|
|
205
|
+
console.print(f" [red]Error retrieving configuration: {e}[/red]")
|
|
206
|
+
console.print()
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _print_registered_libraries() -> None:
|
|
210
|
+
"""Print registered libraries information."""
|
|
211
|
+
console.print("[bold]Registered Libraries:[/bold]")
|
|
212
|
+
try:
|
|
213
|
+
library_names = LibraryRegistry.list_libraries()
|
|
214
|
+
if not library_names:
|
|
215
|
+
console.print(" [yellow]No libraries registered[/yellow]")
|
|
216
|
+
console.print()
|
|
217
|
+
return
|
|
218
|
+
|
|
219
|
+
table = Table(show_header=True, header_style="bold magenta")
|
|
220
|
+
table.add_column("Library Name", style="cyan")
|
|
221
|
+
table.add_column("Version", style="green")
|
|
222
|
+
table.add_column("Engine Version", style="yellow")
|
|
223
|
+
table.add_column("Author", style="blue")
|
|
224
|
+
|
|
225
|
+
for library_name in library_names:
|
|
226
|
+
try:
|
|
227
|
+
library = LibraryRegistry.get_library(library_name)
|
|
228
|
+
metadata = library.get_metadata()
|
|
229
|
+
table.add_row(
|
|
230
|
+
library_name,
|
|
231
|
+
metadata.library_version,
|
|
232
|
+
metadata.engine_version,
|
|
233
|
+
metadata.author,
|
|
234
|
+
)
|
|
235
|
+
except KeyError:
|
|
236
|
+
table.add_row(library_name, "[red]Error[/red]", "[red]Error[/red]", "[red]Error[/red]")
|
|
237
|
+
|
|
238
|
+
console.print(table)
|
|
239
|
+
except Exception as e:
|
|
240
|
+
console.print(f" [red]Error retrieving libraries: {e}[/red]")
|
|
241
|
+
console.print()
|