griptape-nodes 0.43.0__tar.gz → 0.44.0__tar.gz
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-0.43.0 → griptape_nodes-0.44.0}/PKG-INFO +1 -1
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/pyproject.toml +1 -1
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/__init__.py +41 -51
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/app/api.py +35 -6
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/bootstrap/workflow_executors/local_workflow_executor.py +7 -1
- griptape_nodes-0.44.0/src/griptape_nodes/bootstrap/workflow_executors/subprocess_workflow_executor.py +90 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/bootstrap/workflow_executors/workflow_executor.py +7 -1
- griptape_nodes-0.44.0/src/griptape_nodes/drivers/storage/base_storage_driver.py +91 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/drivers/storage/griptape_cloud_storage_driver.py +49 -2
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/drivers/storage/local_storage_driver.py +37 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/exe_types/core_types.py +113 -8
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/exe_types/node_types.py +1 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/machines/control_flow.py +5 -4
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/machines/node_resolution.py +110 -74
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/mcp_server/server.py +16 -8
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/app_events.py +0 -6
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/base_events.py +6 -7
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/flow_events.py +2 -1
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/node_events.py +36 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/os_events.py +98 -6
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/griptape_nodes.py +1 -4
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/config_manager.py +1 -1
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/flow_manager.py +6 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_manager.py +2 -8
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/node_manager.py +76 -5
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/os_manager.py +133 -8
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/workflow_manager.py +54 -5
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/file_system_picker.py +18 -0
- griptape_nodes-0.44.0/src/griptape_nodes/utils/version_utils.py +51 -0
- griptape_nodes-0.43.0/src/griptape_nodes/bootstrap/bootstrap_script.py +0 -54
- griptape_nodes-0.43.0/src/griptape_nodes/bootstrap/post_build_install_script.sh +0 -3
- griptape_nodes-0.43.0/src/griptape_nodes/bootstrap/pre_build_install_script.sh +0 -4
- griptape_nodes-0.43.0/src/griptape_nodes/bootstrap/register_libraries_script.py +0 -32
- griptape_nodes-0.43.0/src/griptape_nodes/bootstrap/structure_config.yaml +0 -15
- griptape_nodes-0.43.0/src/griptape_nodes/bootstrap/workflow_runners/__init__.py +0 -1
- griptape_nodes-0.43.0/src/griptape_nodes/bootstrap/workflow_runners/bootstrap_workflow_runner.py +0 -28
- griptape_nodes-0.43.0/src/griptape_nodes/bootstrap/workflow_runners/local_workflow_runner.py +0 -237
- griptape_nodes-0.43.0/src/griptape_nodes/bootstrap/workflow_runners/subprocess_workflow_runner.py +0 -62
- griptape_nodes-0.43.0/src/griptape_nodes/bootstrap/workflow_runners/workflow_runner.py +0 -11
- griptape_nodes-0.43.0/src/griptape_nodes/drivers/storage/base_storage_driver.py +0 -38
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/README.md +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/app/.python-version +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/app/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/app/app.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/app/watch.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/bootstrap/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/bootstrap/workflow_executors/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/drivers/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/drivers/storage/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/drivers/storage/storage_backend.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/exe_types/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/exe_types/connections.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/exe_types/flow.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/exe_types/type_validator.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/machines/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/machines/fsm.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/mcp_server/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/mcp_server/ws_request_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/node_library/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/node_library/advanced_node_library.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/node_library/library_registry.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/node_library/workflow_registry.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/py.typed +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/agent_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/arbitrary_python_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/config_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/connection_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/context_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/execution_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/generate_request_payload_schemas.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/library_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/logger_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/object_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/parameter_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/payload_registry.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/secrets_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/static_file_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/validation_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/events/workflow_events.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/agent_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/arbitrary_code_exec_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/context_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/engine_identity_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/event_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/data_models.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_directory.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_fsm.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/base.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/github.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/local_file.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/package.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance/sandbox.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_provenance.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/library_lifecycle/library_status.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/object_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/operation_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/secrets_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/session_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/settings.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/static_files_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/managers/version_compatibility_manager.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/retained_mode.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/utils/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/utils/engine_identity.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/retained_mode/utils/name_generator.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/add_param_button.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/button.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/clamp.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/compare.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/compare_images.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/minmax.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/options.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/slider.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/trait_registry.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/traits/traits.json +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/updater/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/updater/__main__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/utils/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/utils/dict_utils.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/utils/image_preview.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/utils/metaclasses.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/version_compatibility/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/version_compatibility/versions/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/version_compatibility/versions/v0_39_0/__init__.py +0 -0
- {griptape_nodes-0.43.0 → griptape_nodes-0.44.0}/src/griptape_nodes/version_compatibility/versions/v0_39_0/modified_parameters_set_removal.py +0 -0
|
@@ -6,7 +6,6 @@ console = Console()
|
|
|
6
6
|
|
|
7
7
|
with console.status("Loading Griptape Nodes...") as status:
|
|
8
8
|
import argparse
|
|
9
|
-
import importlib.metadata
|
|
10
9
|
import json
|
|
11
10
|
import os
|
|
12
11
|
import shutil
|
|
@@ -15,7 +14,7 @@ with console.status("Loading Griptape Nodes...") as status:
|
|
|
15
14
|
import tempfile
|
|
16
15
|
from dataclasses import dataclass
|
|
17
16
|
from pathlib import Path
|
|
18
|
-
from typing import Any
|
|
17
|
+
from typing import Any
|
|
19
18
|
|
|
20
19
|
import httpx
|
|
21
20
|
from rich.box import HEAVY_EDGE
|
|
@@ -28,10 +27,11 @@ with console.status("Loading Griptape Nodes...") as status:
|
|
|
28
27
|
from griptape_nodes.app import start_app
|
|
29
28
|
from griptape_nodes.drivers.storage import StorageBackend
|
|
30
29
|
from griptape_nodes.drivers.storage.griptape_cloud_storage_driver import GriptapeCloudStorageDriver
|
|
31
|
-
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
30
|
+
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
32
31
|
from griptape_nodes.retained_mode.managers.config_manager import ConfigManager
|
|
33
32
|
from griptape_nodes.retained_mode.managers.os_manager import OSManager
|
|
34
33
|
from griptape_nodes.retained_mode.managers.secrets_manager import SecretsManager
|
|
34
|
+
from griptape_nodes.utils.version_utils import get_complete_version_string, get_current_version, get_install_source
|
|
35
35
|
|
|
36
36
|
CONFIG_DIR = xdg_config_home() / "griptape_nodes"
|
|
37
37
|
DATA_DIR = xdg_data_home() / "griptape_nodes"
|
|
@@ -330,7 +330,12 @@ def _get_args() -> argparse.Namespace:
|
|
|
330
330
|
metavar="SUBCOMMAND",
|
|
331
331
|
required=True,
|
|
332
332
|
)
|
|
333
|
-
config_subparsers.add_parser("show", help="Show configuration values.")
|
|
333
|
+
config_show_parser = config_subparsers.add_parser("show", help="Show configuration values.")
|
|
334
|
+
config_show_parser.add_argument(
|
|
335
|
+
"config_path",
|
|
336
|
+
nargs="?",
|
|
337
|
+
help="Optional config path to show specific value (e.g., 'workspace_directory').",
|
|
338
|
+
)
|
|
334
339
|
config_subparsers.add_parser("list", help="List configuration values.")
|
|
335
340
|
config_subparsers.add_parser("reset", help="Reset configuration to defaults.")
|
|
336
341
|
|
|
@@ -609,7 +614,7 @@ def _get_latest_version(package: str, install_source: str) -> str:
|
|
|
609
614
|
return f"v{data['info']['version']}"
|
|
610
615
|
except httpx.HTTPStatusError as e:
|
|
611
616
|
console.print(f"[red]Error fetching latest version: {e}[/red]")
|
|
612
|
-
return
|
|
617
|
+
return get_current_version()
|
|
613
618
|
elif install_source == "git":
|
|
614
619
|
# We only install auto updating from the 'latest' tag
|
|
615
620
|
revision = LATEST_TAG
|
|
@@ -624,20 +629,20 @@ def _get_latest_version(package: str, install_source: str) -> str:
|
|
|
624
629
|
if "object" in data and "sha" in data["object"]:
|
|
625
630
|
return data["object"]["sha"][:7]
|
|
626
631
|
# Should not happen, but if it does, return the current version
|
|
627
|
-
return
|
|
632
|
+
return get_current_version()
|
|
628
633
|
except httpx.HTTPStatusError as e:
|
|
629
634
|
console.print(f"[red]Error fetching latest version: {e}[/red]")
|
|
630
|
-
return
|
|
635
|
+
return get_current_version()
|
|
631
636
|
else:
|
|
632
637
|
# If the package is installed from a file, just return the current version since the user is likely managing it manually
|
|
633
|
-
return
|
|
638
|
+
return get_current_version()
|
|
634
639
|
|
|
635
640
|
|
|
636
641
|
def _auto_update_self() -> None:
|
|
637
642
|
"""Automatically updates the script to the latest version if the user confirms."""
|
|
638
643
|
console.print("[bold green]Checking for updates...[/bold green]")
|
|
639
|
-
source, commit_id =
|
|
640
|
-
current_version =
|
|
644
|
+
source, commit_id = get_install_source()
|
|
645
|
+
current_version = get_current_version()
|
|
641
646
|
latest_version = _get_latest_version(PACKAGE_NAME, source)
|
|
642
647
|
|
|
643
648
|
if source == "git" and commit_id is not None:
|
|
@@ -663,10 +668,10 @@ def _update_self() -> None:
|
|
|
663
668
|
|
|
664
669
|
def _sync_libraries() -> None:
|
|
665
670
|
"""Download and sync Griptape Nodes libraries, copying only directories from synced libraries."""
|
|
666
|
-
install_source, _ =
|
|
671
|
+
install_source, _ = get_install_source()
|
|
667
672
|
# Unless we're installed from PyPi, grab libraries from the 'latest' tag
|
|
668
673
|
if install_source == "pypi":
|
|
669
|
-
version =
|
|
674
|
+
version = get_current_version()
|
|
670
675
|
else:
|
|
671
676
|
version = LATEST_TAG
|
|
672
677
|
|
|
@@ -681,12 +686,13 @@ def _sync_libraries() -> None:
|
|
|
681
686
|
|
|
682
687
|
# Streaming download with a tiny progress bar
|
|
683
688
|
with httpx.stream("GET", tar_url, follow_redirects=True) as r, Progress() as progress:
|
|
689
|
+
task = progress.add_task("[green]Downloading...", total=int(r.headers.get("Content-Length", 0)))
|
|
690
|
+
progress.start()
|
|
684
691
|
try:
|
|
685
692
|
r.raise_for_status()
|
|
686
693
|
except httpx.HTTPStatusError as e:
|
|
687
694
|
console.print(f"[red]Error fetching libraries: {e}[/red]")
|
|
688
695
|
return
|
|
689
|
-
task = progress.add_task("[green]Downloading...", total=int(r.headers.get("Content-Length", 0)))
|
|
690
696
|
with tar_path.open("wb") as f:
|
|
691
697
|
for chunk in r.iter_bytes():
|
|
692
698
|
f.write(chunk)
|
|
@@ -724,18 +730,29 @@ def _sync_libraries() -> None:
|
|
|
724
730
|
|
|
725
731
|
def _print_current_version() -> None:
|
|
726
732
|
"""Prints the current version of the script."""
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
if commit_id is None:
|
|
730
|
-
console.print(f"[bold green]{version} ({source})[/bold green]")
|
|
731
|
-
else:
|
|
732
|
-
console.print(f"[bold green]{version} ({source} - {commit_id})[/bold green]")
|
|
733
|
+
version_string = get_complete_version_string()
|
|
734
|
+
console.print(f"[bold green]{version_string}[/bold green]")
|
|
733
735
|
|
|
734
736
|
|
|
735
|
-
def _print_user_config() -> None:
|
|
736
|
-
"""Prints the user configuration from the config file.
|
|
737
|
-
|
|
738
|
-
|
|
737
|
+
def _print_user_config(config_path: str | None = None) -> None:
|
|
738
|
+
"""Prints the user configuration from the config file.
|
|
739
|
+
|
|
740
|
+
Args:
|
|
741
|
+
config_path: Optional path to specific config value. If None, prints entire config.
|
|
742
|
+
"""
|
|
743
|
+
if config_path is None:
|
|
744
|
+
config = config_manager.merged_config
|
|
745
|
+
sys.stdout.write(json.dumps(config, indent=2))
|
|
746
|
+
else:
|
|
747
|
+
try:
|
|
748
|
+
value = config_manager.get_config_value(config_path)
|
|
749
|
+
if isinstance(value, (dict, list)):
|
|
750
|
+
sys.stdout.write(json.dumps(value, indent=2))
|
|
751
|
+
else:
|
|
752
|
+
sys.stdout.write(str(value))
|
|
753
|
+
except (KeyError, AttributeError, ValueError):
|
|
754
|
+
console.print(f"[bold red]Config path '{config_path}' not found[/bold red]")
|
|
755
|
+
sys.exit(1)
|
|
739
756
|
|
|
740
757
|
|
|
741
758
|
def _list_user_configs() -> None:
|
|
@@ -857,7 +874,7 @@ def _process_args(args: argparse.Namespace) -> None: # noqa: C901, PLR0912
|
|
|
857
874
|
elif args.subcommand == "reset":
|
|
858
875
|
_reset_user_config()
|
|
859
876
|
elif args.subcommand == "show":
|
|
860
|
-
_print_user_config()
|
|
877
|
+
_print_user_config(args.config_path)
|
|
861
878
|
elif args.command == "self":
|
|
862
879
|
if args.subcommand == "update":
|
|
863
880
|
_update_self()
|
|
@@ -873,33 +890,6 @@ def _process_args(args: argparse.Namespace) -> None: # noqa: C901, PLR0912
|
|
|
873
890
|
raise ValueError(msg)
|
|
874
891
|
|
|
875
892
|
|
|
876
|
-
def __get_current_version() -> str:
|
|
877
|
-
"""Returns the current version of the Griptape Nodes package."""
|
|
878
|
-
return f"v{engine_version}"
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
def __get_install_source() -> tuple[Literal["git", "file", "pypi"], str | None]:
|
|
882
|
-
"""Determines the install source of the Griptape Nodes package.
|
|
883
|
-
|
|
884
|
-
Returns:
|
|
885
|
-
tuple: A tuple containing the install source and commit ID (if applicable).
|
|
886
|
-
"""
|
|
887
|
-
dist = importlib.metadata.distribution("griptape_nodes")
|
|
888
|
-
direct_url_text = dist.read_text("direct_url.json")
|
|
889
|
-
# installing from pypi doesn't have a direct_url.json file
|
|
890
|
-
if direct_url_text is None:
|
|
891
|
-
return "pypi", None
|
|
892
|
-
|
|
893
|
-
direct_url_info = json.loads(direct_url_text)
|
|
894
|
-
url = direct_url_info.get("url")
|
|
895
|
-
if url.startswith("file://"):
|
|
896
|
-
return "file", None
|
|
897
|
-
if "vcs_info" in direct_url_info:
|
|
898
|
-
return "git", direct_url_info["vcs_info"].get("commit_id")[:7]
|
|
899
|
-
# Fall back to pypi if no other source is found
|
|
900
|
-
return "pypi", None
|
|
901
|
-
|
|
902
|
-
|
|
903
893
|
def __init_system_config() -> None:
|
|
904
894
|
"""Initializes the system config directory if it doesn't exist."""
|
|
905
895
|
if not CONFIG_DIR.exists():
|
|
@@ -27,9 +27,11 @@ STATIC_SERVER_PORT = int(os.getenv("STATIC_SERVER_PORT", "8124"))
|
|
|
27
27
|
# URL path for the static server
|
|
28
28
|
STATIC_SERVER_URL = os.getenv("STATIC_SERVER_URL", "/static")
|
|
29
29
|
# Log level for the static server
|
|
30
|
-
STATIC_SERVER_LOG_LEVEL = os.getenv("STATIC_SERVER_LOG_LEVEL", "
|
|
30
|
+
STATIC_SERVER_LOG_LEVEL = os.getenv("STATIC_SERVER_LOG_LEVEL", "ERROR").lower()
|
|
31
31
|
|
|
32
32
|
logger = logging.getLogger("griptape_nodes_api")
|
|
33
|
+
logging.getLogger("uvicorn").addHandler(RichHandler(show_time=True, show_path=False, markup=True, rich_tracebacks=True))
|
|
34
|
+
|
|
33
35
|
|
|
34
36
|
# Global event queue - initialized as None and set when starting the API
|
|
35
37
|
event_queue: Queue | None = None
|
|
@@ -124,6 +126,37 @@ async def _list_static_files(static_directory: Annotated[Path, Depends(get_stati
|
|
|
124
126
|
return {"files": file_names}
|
|
125
127
|
|
|
126
128
|
|
|
129
|
+
@app.delete("/static-files/{file_path:path}")
|
|
130
|
+
async def _delete_static_file(file_path: str, static_directory: Annotated[Path, Depends(get_static_dir)]) -> dict:
|
|
131
|
+
"""Delete a static file from the static server."""
|
|
132
|
+
if not STATIC_SERVER_ENABLED:
|
|
133
|
+
msg = "Static server is not enabled. Please set STATIC_SERVER_ENABLED to True."
|
|
134
|
+
raise HTTPException(status_code=500, detail=msg)
|
|
135
|
+
|
|
136
|
+
file_full_path = Path(static_directory / file_path)
|
|
137
|
+
|
|
138
|
+
# Check if file exists
|
|
139
|
+
if not file_full_path.exists():
|
|
140
|
+
logger.warning("File not found for deletion: %s", file_path)
|
|
141
|
+
raise HTTPException(status_code=404, detail=f"File {file_path} not found")
|
|
142
|
+
|
|
143
|
+
# Check if it's actually a file (not a directory)
|
|
144
|
+
if not file_full_path.is_file():
|
|
145
|
+
msg = f"Path {file_path} is not a file"
|
|
146
|
+
logger.error(msg)
|
|
147
|
+
raise HTTPException(status_code=400, detail=msg)
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
file_full_path.unlink()
|
|
151
|
+
except (OSError, PermissionError) as e:
|
|
152
|
+
msg = f"Failed to delete file {file_path}: {e}"
|
|
153
|
+
logger.error(msg)
|
|
154
|
+
raise HTTPException(status_code=500, detail=msg) from e
|
|
155
|
+
else:
|
|
156
|
+
logger.info("Successfully deleted static file: %s", file_path)
|
|
157
|
+
return {"message": f"File {file_path} deleted successfully"}
|
|
158
|
+
|
|
159
|
+
|
|
127
160
|
@app.post("/engines/request")
|
|
128
161
|
async def _create_event(request: Request, queue: Annotated[Queue, Depends(get_event_queue)]) -> None:
|
|
129
162
|
body = await request.json()
|
|
@@ -136,10 +169,6 @@ def start_api(static_directory: Path, queue: Queue) -> None:
|
|
|
136
169
|
event_queue = queue
|
|
137
170
|
static_dir = static_directory
|
|
138
171
|
|
|
139
|
-
logging.getLogger("uvicorn").addHandler(
|
|
140
|
-
RichHandler(show_time=True, show_path=False, markup=True, rich_tracebacks=True)
|
|
141
|
-
)
|
|
142
|
-
|
|
143
172
|
if not static_dir.exists():
|
|
144
173
|
static_dir.mkdir(parents=True, exist_ok=True)
|
|
145
174
|
|
|
@@ -151,7 +180,7 @@ def start_api(static_directory: Path, queue: Queue) -> None:
|
|
|
151
180
|
"http://localhost:5173",
|
|
152
181
|
],
|
|
153
182
|
allow_credentials=True,
|
|
154
|
-
allow_methods=["OPTIONS", "GET", "POST", "PUT"],
|
|
183
|
+
allow_methods=["OPTIONS", "GET", "POST", "PUT", "DELETE"],
|
|
155
184
|
allow_headers=["*"],
|
|
156
185
|
)
|
|
157
186
|
|
|
@@ -144,7 +144,13 @@ class LocalWorkflowExecutor(WorkflowExecutor):
|
|
|
144
144
|
|
|
145
145
|
return output
|
|
146
146
|
|
|
147
|
-
def run(
|
|
147
|
+
def run(
|
|
148
|
+
self,
|
|
149
|
+
workflow_name: str,
|
|
150
|
+
flow_input: Any,
|
|
151
|
+
storage_backend: StorageBackend = StorageBackend.LOCAL,
|
|
152
|
+
**kwargs: Any, # noqa: ARG002
|
|
153
|
+
) -> None:
|
|
148
154
|
"""Executes a local workflow.
|
|
149
155
|
|
|
150
156
|
Executes a workflow by setting up event listeners, registering libraries,
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
import sys
|
|
3
|
+
import threading
|
|
4
|
+
from multiprocessing import Process, Queue
|
|
5
|
+
from multiprocessing import Queue as ProcessQueue
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from griptape_nodes.app.api import start_api
|
|
10
|
+
from griptape_nodes.app.app import _build_static_dir
|
|
11
|
+
from griptape_nodes.bootstrap.workflow_executors.local_workflow_executor import LocalWorkflowExecutor
|
|
12
|
+
from griptape_nodes.bootstrap.workflow_executors.workflow_executor import WorkflowExecutor
|
|
13
|
+
from griptape_nodes.drivers.storage.storage_backend import StorageBackend
|
|
14
|
+
from griptape_nodes.retained_mode.griptape_nodes import GriptapeNodes
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SubprocessWorkflowExecutor(WorkflowExecutor):
|
|
18
|
+
@classmethod
|
|
19
|
+
def load_workflow(cls, path_to_workflow: str) -> None:
|
|
20
|
+
"""Load a workflow from a file."""
|
|
21
|
+
# Ensure file_path is a Path object
|
|
22
|
+
file_path = Path(path_to_workflow)
|
|
23
|
+
|
|
24
|
+
# Generate a unique module name
|
|
25
|
+
module_name = f"gtn_dynamic_module_{file_path.name.replace('.', '_')}_{hash(str(file_path))}"
|
|
26
|
+
|
|
27
|
+
# Load the module specification
|
|
28
|
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
|
29
|
+
if spec is None or spec.loader is None:
|
|
30
|
+
msg = f"Could not load module specification from {file_path}"
|
|
31
|
+
raise ImportError(msg)
|
|
32
|
+
|
|
33
|
+
# Create the module
|
|
34
|
+
module = importlib.util.module_from_spec(spec)
|
|
35
|
+
|
|
36
|
+
# Add to sys.modules to handle recursive imports
|
|
37
|
+
sys.modules[module_name] = module
|
|
38
|
+
|
|
39
|
+
# Execute the module
|
|
40
|
+
spec.loader.exec_module(module)
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def _subprocess_entry(
|
|
44
|
+
exception_queue: Queue,
|
|
45
|
+
workflow_name: str,
|
|
46
|
+
flow_input: Any,
|
|
47
|
+
workflow_path: str | None = None,
|
|
48
|
+
) -> None:
|
|
49
|
+
try:
|
|
50
|
+
static_dir = _build_static_dir()
|
|
51
|
+
event_queue = ProcessQueue()
|
|
52
|
+
threading.Thread(target=start_api, args=(static_dir, event_queue), daemon=True).start()
|
|
53
|
+
|
|
54
|
+
if workflow_path:
|
|
55
|
+
SubprocessWorkflowExecutor.load_workflow(workflow_path)
|
|
56
|
+
context_manager = GriptapeNodes.ContextManager()
|
|
57
|
+
workflow_name = context_manager.get_current_workflow_name()
|
|
58
|
+
|
|
59
|
+
workflow_runner = LocalWorkflowExecutor()
|
|
60
|
+
workflow_runner.run(workflow_name, flow_input, StorageBackend.LOCAL)
|
|
61
|
+
except Exception as e:
|
|
62
|
+
exception_queue.put(e)
|
|
63
|
+
raise
|
|
64
|
+
|
|
65
|
+
def run(
|
|
66
|
+
self,
|
|
67
|
+
workflow_name: str,
|
|
68
|
+
flow_input: Any,
|
|
69
|
+
storage_backend: StorageBackend = StorageBackend.LOCAL, # noqa: ARG002
|
|
70
|
+
**kwargs: Any,
|
|
71
|
+
) -> None:
|
|
72
|
+
workflow_path = kwargs.get("workflow_path")
|
|
73
|
+
exception_queue = Queue()
|
|
74
|
+
process = Process(
|
|
75
|
+
target=self._subprocess_entry,
|
|
76
|
+
args=(exception_queue, workflow_name, flow_input, workflow_path),
|
|
77
|
+
)
|
|
78
|
+
process.start()
|
|
79
|
+
process.join()
|
|
80
|
+
|
|
81
|
+
if not exception_queue.empty():
|
|
82
|
+
exception = exception_queue.get_nowait()
|
|
83
|
+
if isinstance(exception, Exception):
|
|
84
|
+
raise exception
|
|
85
|
+
msg = f"Expected an Exception but got: {type(exception)}"
|
|
86
|
+
raise RuntimeError(msg)
|
|
87
|
+
|
|
88
|
+
if process.exitcode != 0:
|
|
89
|
+
msg = f"Process exited with code {process.exitcode} but no exception was raised."
|
|
90
|
+
raise RuntimeError(msg)
|
|
@@ -9,5 +9,11 @@ logger = logging.getLogger(__name__)
|
|
|
9
9
|
|
|
10
10
|
class WorkflowExecutor(ABC):
|
|
11
11
|
@abstractmethod
|
|
12
|
-
def run(
|
|
12
|
+
def run(
|
|
13
|
+
self,
|
|
14
|
+
workflow_name: str,
|
|
15
|
+
flow_input: Any,
|
|
16
|
+
storage_backend: StorageBackend = StorageBackend.LOCAL,
|
|
17
|
+
**kwargs: Any,
|
|
18
|
+
) -> None:
|
|
13
19
|
pass
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import TypedDict
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger("griptape_nodes")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CreateSignedUploadUrlResponse(TypedDict):
|
|
11
|
+
"""Response type for create_signed_upload_url method."""
|
|
12
|
+
|
|
13
|
+
url: str
|
|
14
|
+
headers: dict
|
|
15
|
+
method: str
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BaseStorageDriver(ABC):
|
|
19
|
+
"""Base class for storage drivers."""
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def create_signed_upload_url(self, file_name: str) -> CreateSignedUploadUrlResponse:
|
|
23
|
+
"""Create a signed upload URL for the given file name.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
file_name: The name of the file to create a signed URL for.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
CreateSignedUploadUrlResponse: A dictionary containing the signed URL, headers, and operation type.
|
|
30
|
+
"""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
@abstractmethod
|
|
34
|
+
def create_signed_download_url(self, file_name: str) -> str:
|
|
35
|
+
"""Create a signed download URL for the given file name.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
file_name: The name of the file to create a signed URL for.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
str: The signed URL for downloading the file.
|
|
42
|
+
"""
|
|
43
|
+
...
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def delete_file(self, file_name: str) -> None:
|
|
47
|
+
"""Delete a file from storage.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
file_name: The name of the file to delete.
|
|
51
|
+
"""
|
|
52
|
+
...
|
|
53
|
+
|
|
54
|
+
@abstractmethod
|
|
55
|
+
def list_files(self) -> list[str]:
|
|
56
|
+
"""List all files in storage.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
A list of file names in storage.
|
|
60
|
+
"""
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
def download_file(self, file_name: str) -> bytes:
|
|
64
|
+
"""Download a file from the bucket.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
file_name: The name of the file to download.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
The file content as bytes.
|
|
71
|
+
|
|
72
|
+
Raises:
|
|
73
|
+
RuntimeError: If file download fails.
|
|
74
|
+
"""
|
|
75
|
+
try:
|
|
76
|
+
# Get signed download URL
|
|
77
|
+
download_url = self.create_signed_download_url(file_name)
|
|
78
|
+
|
|
79
|
+
# Download the file
|
|
80
|
+
response = httpx.get(download_url)
|
|
81
|
+
response.raise_for_status()
|
|
82
|
+
except httpx.HTTPStatusError as e:
|
|
83
|
+
msg = f"Failed to download file {file_name}: {e}"
|
|
84
|
+
logger.error(msg)
|
|
85
|
+
raise RuntimeError(msg) from e
|
|
86
|
+
except Exception as e:
|
|
87
|
+
msg = f"Unexpected error downloading file {file_name}: {e}"
|
|
88
|
+
logger.error(msg)
|
|
89
|
+
raise RuntimeError(msg) from e
|
|
90
|
+
else:
|
|
91
|
+
return response.content
|
|
@@ -76,8 +76,7 @@ class GriptapeCloudStorageDriver(BaseStorageDriver):
|
|
|
76
76
|
return {"url": response_data["url"], "headers": response_data.get("headers", {}), "method": "PUT"}
|
|
77
77
|
|
|
78
78
|
def create_signed_download_url(self, file_name: str) -> str:
|
|
79
|
-
|
|
80
|
-
url = urljoin(self.base_url, f"/api/buckets/{self.bucket_id}/asset-urls/{full_file_path}")
|
|
79
|
+
url = urljoin(self.base_url, f"/api/buckets/{self.bucket_id}/asset-urls/{file_name}")
|
|
81
80
|
try:
|
|
82
81
|
response = httpx.post(url, json={"method": "GET"}, headers=self.headers)
|
|
83
82
|
response.raise_for_status()
|
|
@@ -135,6 +134,37 @@ class GriptapeCloudStorageDriver(BaseStorageDriver):
|
|
|
135
134
|
logger.info("Created new Griptape Cloud bucket '%s' with ID: %s", bucket_name, bucket_id)
|
|
136
135
|
return bucket_id
|
|
137
136
|
|
|
137
|
+
def list_files(self) -> list[str]:
|
|
138
|
+
"""List all files in storage.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
A list of file names in storage.
|
|
142
|
+
|
|
143
|
+
Raises:
|
|
144
|
+
RuntimeError: If file listing fails.
|
|
145
|
+
"""
|
|
146
|
+
url = urljoin(self.base_url, f"/api/buckets/{self.bucket_id}/assets")
|
|
147
|
+
try:
|
|
148
|
+
response = httpx.get(url, headers=self.headers, params={"prefix": self.static_files_directory or ""})
|
|
149
|
+
response.raise_for_status()
|
|
150
|
+
except httpx.HTTPStatusError as e:
|
|
151
|
+
msg = f"Failed to list files in bucket {self.bucket_id}: {e}"
|
|
152
|
+
logger.error(msg)
|
|
153
|
+
raise RuntimeError(msg) from e
|
|
154
|
+
|
|
155
|
+
response_data = response.json()
|
|
156
|
+
assets = response_data.get("assets", [])
|
|
157
|
+
|
|
158
|
+
file_names = []
|
|
159
|
+
for asset in assets:
|
|
160
|
+
name = asset.get("name", "")
|
|
161
|
+
# Remove the static files directory prefix if it exists
|
|
162
|
+
if self.static_files_directory and name.startswith(f"{self.static_files_directory}/"):
|
|
163
|
+
name = name[len(f"{self.static_files_directory}/") :]
|
|
164
|
+
file_names.append(name)
|
|
165
|
+
|
|
166
|
+
return file_names
|
|
167
|
+
|
|
138
168
|
@staticmethod
|
|
139
169
|
def list_buckets(*, base_url: str, api_key: str) -> list[dict]:
|
|
140
170
|
"""List all buckets in Griptape Cloud.
|
|
@@ -158,3 +188,20 @@ class GriptapeCloudStorageDriver(BaseStorageDriver):
|
|
|
158
188
|
raise RuntimeError(msg) from e
|
|
159
189
|
|
|
160
190
|
return response.json().get("buckets", [])
|
|
191
|
+
|
|
192
|
+
def delete_file(self, file_name: str) -> None:
|
|
193
|
+
"""Delete a file from the bucket.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
file_name: The name of the file to delete.
|
|
197
|
+
"""
|
|
198
|
+
full_file_path = self._get_full_file_path(file_name)
|
|
199
|
+
url = urljoin(self.base_url, f"/api/buckets/{self.bucket_id}/assets/{full_file_path}")
|
|
200
|
+
|
|
201
|
+
try:
|
|
202
|
+
response = httpx.delete(url, headers=self.headers)
|
|
203
|
+
response.raise_for_status()
|
|
204
|
+
except httpx.HTTPStatusError as e:
|
|
205
|
+
msg = f"Failed to delete file {file_name}: {e}"
|
|
206
|
+
logger.error(msg)
|
|
207
|
+
raise RuntimeError(msg) from e
|
|
@@ -53,3 +53,40 @@ class LocalStorageDriver(BaseStorageDriver):
|
|
|
53
53
|
# Add a cache-busting query parameter to the URL so that the browser always reloads the file
|
|
54
54
|
cache_busted_url = f"{url}?t={int(time.time())}"
|
|
55
55
|
return cache_busted_url
|
|
56
|
+
|
|
57
|
+
def delete_file(self, file_name: str) -> None:
|
|
58
|
+
"""Delete a file from local storage.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
file_name: The name of the file to delete.
|
|
62
|
+
"""
|
|
63
|
+
# Use the static server's delete endpoint
|
|
64
|
+
delete_url = urljoin(self.base_url, f"/static-files/{file_name}")
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
response = httpx.delete(delete_url)
|
|
68
|
+
response.raise_for_status()
|
|
69
|
+
except httpx.HTTPStatusError as e:
|
|
70
|
+
msg = f"Failed to delete file {file_name}: {e}"
|
|
71
|
+
logger.error(msg)
|
|
72
|
+
raise RuntimeError(msg) from e
|
|
73
|
+
|
|
74
|
+
def list_files(self) -> list[str]:
|
|
75
|
+
"""List all files in local storage.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
A list of file names in storage.
|
|
79
|
+
"""
|
|
80
|
+
# Use the static server's list endpoint
|
|
81
|
+
list_url = urljoin(self.base_url, "/static-uploads/")
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
response = httpx.get(list_url)
|
|
85
|
+
response.raise_for_status()
|
|
86
|
+
except httpx.HTTPStatusError as e:
|
|
87
|
+
msg = f"Failed to list files: {e}"
|
|
88
|
+
logger.error(msg)
|
|
89
|
+
raise RuntimeError(msg) from e
|
|
90
|
+
|
|
91
|
+
response_data = response.json()
|
|
92
|
+
return response_data.get("files", [])
|