dtSpark 1.1.0a2__py3-none-any.whl → 1.1.0a6__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.
- dtSpark/_version.txt +1 -1
- dtSpark/aws/authentication.py +1 -1
- dtSpark/aws/bedrock.py +238 -239
- dtSpark/aws/costs.py +9 -5
- dtSpark/aws/pricing.py +25 -21
- dtSpark/cli_interface.py +69 -62
- dtSpark/conversation_manager.py +54 -47
- dtSpark/core/application.py +151 -111
- dtSpark/core/context_compaction.py +241 -226
- dtSpark/daemon/__init__.py +36 -22
- dtSpark/daemon/action_monitor.py +46 -17
- dtSpark/daemon/daemon_app.py +126 -104
- dtSpark/daemon/daemon_manager.py +59 -23
- dtSpark/daemon/pid_file.py +3 -2
- dtSpark/database/autonomous_actions.py +3 -0
- dtSpark/database/credential_prompt.py +52 -54
- dtSpark/files/manager.py +6 -12
- dtSpark/limits/__init__.py +1 -1
- dtSpark/limits/tokens.py +2 -2
- dtSpark/llm/anthropic_direct.py +246 -141
- dtSpark/llm/ollama.py +3 -1
- dtSpark/mcp_integration/manager.py +4 -4
- dtSpark/mcp_integration/tool_selector.py +83 -77
- dtSpark/resources/config.yaml.template +10 -0
- dtSpark/safety/patterns.py +45 -46
- dtSpark/safety/prompt_inspector.py +8 -1
- dtSpark/scheduler/creation_tools.py +273 -181
- dtSpark/scheduler/executor.py +503 -221
- dtSpark/tools/builtin.py +70 -53
- dtSpark/web/endpoints/autonomous_actions.py +12 -9
- dtSpark/web/endpoints/chat.py +18 -6
- dtSpark/web/endpoints/conversations.py +57 -17
- dtSpark/web/endpoints/main_menu.py +132 -105
- dtSpark/web/endpoints/streaming.py +2 -2
- dtSpark/web/server.py +65 -5
- dtSpark/web/ssl_utils.py +3 -3
- dtSpark/web/static/css/dark-theme.css +8 -29
- dtSpark/web/static/js/actions.js +2 -1
- dtSpark/web/static/js/chat.js +6 -8
- dtSpark/web/static/js/main.js +8 -8
- dtSpark/web/static/js/sse-client.js +130 -122
- dtSpark/web/templates/actions.html +5 -5
- dtSpark/web/templates/base.html +13 -0
- dtSpark/web/templates/chat.html +52 -50
- dtSpark/web/templates/conversations.html +50 -22
- dtSpark/web/templates/goodbye.html +2 -2
- dtSpark/web/templates/main_menu.html +17 -17
- dtSpark/web/templates/new_conversation.html +51 -20
- dtSpark/web/web_interface.py +2 -2
- {dtspark-1.1.0a2.dist-info → dtspark-1.1.0a6.dist-info}/METADATA +9 -2
- dtspark-1.1.0a6.dist-info/RECORD +96 -0
- dtspark-1.1.0a2.dist-info/RECORD +0 -96
- {dtspark-1.1.0a2.dist-info → dtspark-1.1.0a6.dist-info}/WHEEL +0 -0
- {dtspark-1.1.0a2.dist-info → dtspark-1.1.0a6.dist-info}/entry_points.txt +0 -0
- {dtspark-1.1.0a2.dist-info → dtspark-1.1.0a6.dist-info}/licenses/LICENSE +0 -0
- {dtspark-1.1.0a2.dist-info → dtspark-1.1.0a6.dist-info}/top_level.txt +0 -0
dtSpark/core/application.py
CHANGED
|
@@ -84,6 +84,16 @@ def copy_to_clipboard(text: str) -> bool:
|
|
|
84
84
|
logging.error(f"Failed to copy to clipboard: {e}")
|
|
85
85
|
return False
|
|
86
86
|
|
|
87
|
+
# Common string constants (SonarCloud S1192)
|
|
88
|
+
_SETTING_BEDROCK_COST_TRACKING = 'llm_providers.aws_bedrock.cost_tracking.enabled'
|
|
89
|
+
_SETTING_COST_TRACKING = 'aws.cost_tracking.enabled'
|
|
90
|
+
_SETTING_OLLAMA_ENABLED = 'llm_providers.ollama.enabled'
|
|
91
|
+
_DEFAULT_RUNNING_DIR = "./running"
|
|
92
|
+
_PROMPT_ACCESS_MODE = "Select access mode"
|
|
93
|
+
_MSG_NO_MODELS = "No models available"
|
|
94
|
+
_MSG_MANAGED_CONVERSATION = "This conversation is managed by configuration"
|
|
95
|
+
_MSG_DELETE_CANCELLED = "Delete operation cancelled"
|
|
96
|
+
|
|
87
97
|
class AWSBedrockCLI(AbstractApp):
|
|
88
98
|
def __init__(self):
|
|
89
99
|
super().__init__(short_name=agent_type(), full_name=full_name(), version=version(),
|
|
@@ -371,10 +381,11 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
371
381
|
aws_session_token = self.settings.get('aws.session_token', None)
|
|
372
382
|
|
|
373
383
|
# Configure CLI cost tracking display
|
|
374
|
-
cost_tracking_enabled = self._get_nested_setting(
|
|
384
|
+
cost_tracking_enabled = self._get_nested_setting(_SETTING_BEDROCK_COST_TRACKING, None)
|
|
375
385
|
if cost_tracking_enabled is None:
|
|
376
|
-
cost_tracking_enabled = self.settings.get(
|
|
386
|
+
cost_tracking_enabled = self.settings.get(_SETTING_COST_TRACKING, False)
|
|
377
387
|
self.cli.cost_tracking_enabled = cost_tracking_enabled
|
|
388
|
+
self.cli.actions_enabled = self._get_nested_setting('autonomous_actions.enabled', False)
|
|
378
389
|
|
|
379
390
|
progress.update(task_config, advance=100)
|
|
380
391
|
|
|
@@ -391,7 +402,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
391
402
|
# Handle missing or various value types
|
|
392
403
|
if aws_enabled_raw is None:
|
|
393
404
|
# Setting not found via any method - check if other providers are enabled
|
|
394
|
-
ollama_check = self._get_nested_setting(
|
|
405
|
+
ollama_check = self._get_nested_setting(_SETTING_OLLAMA_ENABLED, False)
|
|
395
406
|
anthropic_check = self._get_nested_setting('llm_providers.anthropic.enabled', False)
|
|
396
407
|
if ollama_check or anthropic_check:
|
|
397
408
|
# Other providers configured, don't default to AWS
|
|
@@ -432,7 +443,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
432
443
|
self.cli.print_warning("Failed to authenticate with AWS Bedrock")
|
|
433
444
|
|
|
434
445
|
# Check if Ollama is available as fallback
|
|
435
|
-
ollama_enabled = self._get_nested_setting(
|
|
446
|
+
ollama_enabled = self._get_nested_setting(_SETTING_OLLAMA_ENABLED, False)
|
|
436
447
|
if not ollama_enabled:
|
|
437
448
|
self.cli.print_error("AWS authentication required (Ollama not configured)")
|
|
438
449
|
self.cli.print_info(f"Run: aws sso login --profile {aws_profile}")
|
|
@@ -457,7 +468,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
457
468
|
progress.update(task_llm, advance=20, description="[cyan]Checking Ollama...")
|
|
458
469
|
|
|
459
470
|
# Check Ollama configuration
|
|
460
|
-
ollama_enabled = self._get_nested_setting(
|
|
471
|
+
ollama_enabled = self._get_nested_setting(_SETTING_OLLAMA_ENABLED, False)
|
|
461
472
|
if ollama_enabled:
|
|
462
473
|
try:
|
|
463
474
|
ollama_url = self._get_nested_setting(
|
|
@@ -529,9 +540,9 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
529
540
|
|
|
530
541
|
# Task 3.5: Retrieve Bedrock cost information (silently, display later)
|
|
531
542
|
# Only if cost tracking is enabled in configuration
|
|
532
|
-
cost_tracking_enabled = self._get_nested_setting(
|
|
543
|
+
cost_tracking_enabled = self._get_nested_setting(_SETTING_BEDROCK_COST_TRACKING, None)
|
|
533
544
|
if cost_tracking_enabled is None:
|
|
534
|
-
cost_tracking_enabled = self.settings.get(
|
|
545
|
+
cost_tracking_enabled = self.settings.get(_SETTING_COST_TRACKING, False)
|
|
535
546
|
if cost_tracking_enabled and self.authenticator:
|
|
536
547
|
task_costs = progress.add_task("[cyan]Retrieving usage costs...", total=100)
|
|
537
548
|
self.bedrock_costs = None
|
|
@@ -796,77 +807,87 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
796
807
|
)
|
|
797
808
|
progress.update(task_conv, advance=100)
|
|
798
809
|
|
|
799
|
-
# Task 7: Initialise autonomous action scheduler
|
|
810
|
+
# Task 7: Initialise autonomous action scheduler (if enabled)
|
|
811
|
+
self.actions_enabled = self._get_nested_setting('autonomous_actions.enabled', False)
|
|
800
812
|
task_scheduler = progress.add_task("[cyan]Initialising action scheduler...", total=100)
|
|
801
|
-
try:
|
|
802
|
-
from dtSpark.scheduler import (
|
|
803
|
-
ActionSchedulerManager,
|
|
804
|
-
ActionExecutionQueue,
|
|
805
|
-
ActionExecutor
|
|
806
|
-
)
|
|
807
813
|
|
|
808
|
-
|
|
809
|
-
|
|
814
|
+
if not self.actions_enabled:
|
|
815
|
+
logging.info("Autonomous actions are disabled via configuration")
|
|
816
|
+
self.action_scheduler = None
|
|
817
|
+
self.execution_queue = None
|
|
818
|
+
self.action_executor = None
|
|
819
|
+
self.daemon_is_running = False
|
|
820
|
+
progress.update(task_scheduler, advance=100)
|
|
821
|
+
else:
|
|
822
|
+
try:
|
|
823
|
+
from dtSpark.scheduler import (
|
|
824
|
+
ActionSchedulerManager,
|
|
825
|
+
ActionExecutionQueue,
|
|
826
|
+
ActionExecutor
|
|
827
|
+
)
|
|
810
828
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
if self.mcp_manager:
|
|
814
|
-
def get_tools_func():
|
|
815
|
-
import asyncio
|
|
816
|
-
loop = getattr(self.mcp_manager, '_initialization_loop', None)
|
|
817
|
-
if loop and not loop.is_closed():
|
|
818
|
-
return loop.run_until_complete(self.mcp_manager.list_all_tools())
|
|
819
|
-
return []
|
|
820
|
-
|
|
821
|
-
self.action_executor = ActionExecutor(
|
|
822
|
-
database=self.database,
|
|
823
|
-
llm_manager=self.llm_manager,
|
|
824
|
-
mcp_manager=self.mcp_manager,
|
|
825
|
-
get_tools_func=get_tools_func,
|
|
826
|
-
config=config_for_manager
|
|
827
|
-
)
|
|
829
|
+
# Get database path for scheduler job store
|
|
830
|
+
db_path = self.database.db_path or ':memory:'
|
|
828
831
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
832
|
+
# Create executor with LLM manager and optional MCP manager
|
|
833
|
+
get_tools_func = None
|
|
834
|
+
if self.mcp_manager:
|
|
835
|
+
def get_tools_func():
|
|
836
|
+
import asyncio
|
|
837
|
+
loop = getattr(self.mcp_manager, '_initialization_loop', None)
|
|
838
|
+
if loop and not loop.is_closed():
|
|
839
|
+
return loop.run_until_complete(self.mcp_manager.list_all_tools())
|
|
840
|
+
return []
|
|
841
|
+
|
|
842
|
+
self.action_executor = ActionExecutor(
|
|
843
|
+
database=self.database,
|
|
844
|
+
llm_manager=self.llm_manager,
|
|
845
|
+
mcp_manager=self.mcp_manager,
|
|
846
|
+
get_tools_func=get_tools_func,
|
|
847
|
+
config=config_for_manager
|
|
848
|
+
)
|
|
833
849
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
execution_callback=lambda action_id, user_guid: self.execution_queue.enqueue(
|
|
838
|
-
action_id, user_guid, is_manual=False
|
|
850
|
+
# Create execution queue
|
|
851
|
+
self.execution_queue = ActionExecutionQueue(
|
|
852
|
+
executor_func=self.action_executor.execute
|
|
839
853
|
)
|
|
840
|
-
)
|
|
841
854
|
|
|
842
|
-
|
|
843
|
-
|
|
855
|
+
# Create scheduler manager
|
|
856
|
+
self.action_scheduler = ActionSchedulerManager(
|
|
857
|
+
db_path=db_path,
|
|
858
|
+
execution_callback=lambda action_id, user_guid: self.execution_queue.enqueue(
|
|
859
|
+
action_id, user_guid, is_manual=False
|
|
860
|
+
)
|
|
861
|
+
)
|
|
844
862
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
self.action_scheduler.initialise()
|
|
848
|
-
self.execution_queue.start()
|
|
863
|
+
# Check if daemon is running (for warning display later)
|
|
864
|
+
self.daemon_is_running = self._check_daemon_running()
|
|
849
865
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
logging.warning("Daemon is not running - scheduled actions will NOT execute until daemon is started")
|
|
866
|
+
# Initialise execution components (for manual "Run Now" from UI)
|
|
867
|
+
# Note: Scheduled execution is ONLY handled by the daemon process
|
|
868
|
+
self.action_scheduler.initialise()
|
|
869
|
+
self.execution_queue.start()
|
|
855
870
|
|
|
856
|
-
|
|
871
|
+
# UI never starts the scheduler - daemon handles all scheduled execution
|
|
872
|
+
if self.daemon_is_running:
|
|
873
|
+
logging.info("Daemon is running - scheduled actions will be executed by daemon")
|
|
874
|
+
else:
|
|
875
|
+
logging.warning("Daemon is not running - scheduled actions will NOT execute until daemon is started")
|
|
857
876
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
877
|
+
progress.update(task_scheduler, advance=100)
|
|
878
|
+
|
|
879
|
+
except ImportError as e:
|
|
880
|
+
logging.warning(f"Action scheduler not available (APScheduler not installed): {e}")
|
|
881
|
+
self.action_scheduler = None
|
|
882
|
+
self.execution_queue = None
|
|
883
|
+
self.action_executor = None
|
|
884
|
+
progress.update(task_scheduler, advance=100)
|
|
885
|
+
except Exception as e:
|
|
886
|
+
logging.error(f"Failed to initialise action scheduler: {e}")
|
|
887
|
+
self.action_scheduler = None
|
|
888
|
+
self.execution_queue = None
|
|
889
|
+
self.action_executor = None
|
|
890
|
+
progress.update(task_scheduler, advance=100)
|
|
870
891
|
|
|
871
892
|
# Display application info first (user identification)
|
|
872
893
|
self.cli.display_application_info(self.user_guid)
|
|
@@ -881,8 +902,8 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
881
902
|
if mcp_enabled and self.mcp_manager:
|
|
882
903
|
self.cli.display_mcp_status(self.mcp_manager)
|
|
883
904
|
|
|
884
|
-
# Display daemon status warning if daemon is not running
|
|
885
|
-
if hasattr(self, 'daemon_is_running') and not self.daemon_is_running:
|
|
905
|
+
# Display daemon status warning if daemon is not running (only when actions are enabled)
|
|
906
|
+
if self.actions_enabled and hasattr(self, 'daemon_is_running') and not self.daemon_is_running:
|
|
886
907
|
# Check if there are any scheduled actions
|
|
887
908
|
try:
|
|
888
909
|
actions = self.database.get_all_actions(include_disabled=False)
|
|
@@ -1016,8 +1037,9 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
1016
1037
|
logging.debug("Predefined conversations not enabled in config")
|
|
1017
1038
|
return
|
|
1018
1039
|
|
|
1019
|
-
# Get the mandatory model
|
|
1040
|
+
# Get the mandatory model and provider settings
|
|
1020
1041
|
mandatory_model = self._get_nested_setting('llm_providers.mandatory_model', None)
|
|
1042
|
+
mandatory_provider = self._get_nested_setting('llm_providers.mandatory_provider', None)
|
|
1021
1043
|
|
|
1022
1044
|
# Get list of predefined conversations
|
|
1023
1045
|
predefined_convs = self.settings.get('predefined_conversations.conversations', [])
|
|
@@ -1135,27 +1157,45 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
1135
1157
|
if not source or not source.strip():
|
|
1136
1158
|
return source
|
|
1137
1159
|
|
|
1138
|
-
|
|
1139
|
-
try:
|
|
1140
|
-
resource_content = ResourceManager().load_resource(source)
|
|
1141
|
-
if resource_content is not None:
|
|
1142
|
-
logging.info(f"Loaded {description} via ResourceManager from: {source}")
|
|
1143
|
-
return resource_content
|
|
1144
|
-
except Exception as e:
|
|
1145
|
-
logging.debug(f"ResourceManager could not load {description} from '{source}': {e}")
|
|
1160
|
+
import os
|
|
1146
1161
|
|
|
1147
|
-
#
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1162
|
+
# Determine if source looks like a file path or resource name
|
|
1163
|
+
# (contains path separators, has a file extension, or doesn't contain spaces)
|
|
1164
|
+
looks_like_path = (
|
|
1165
|
+
os.sep in source
|
|
1166
|
+
or '/' in source
|
|
1167
|
+
or '\\' in source
|
|
1168
|
+
or (
|
|
1169
|
+
'.' in source
|
|
1170
|
+
and not source.strip().endswith('.')
|
|
1171
|
+
and ' ' not in source.strip()
|
|
1172
|
+
)
|
|
1173
|
+
)
|
|
1174
|
+
|
|
1175
|
+
if looks_like_path:
|
|
1176
|
+
# Try ResourceManager first (for package resources)
|
|
1177
|
+
try:
|
|
1178
|
+
resource_content = ResourceManager().load_resource(source)
|
|
1179
|
+
if resource_content is not None:
|
|
1180
|
+
logging.info(f"Loaded {description} via ResourceManager from: {source}")
|
|
1181
|
+
return resource_content
|
|
1182
|
+
except Exception as e:
|
|
1183
|
+
logging.debug(f"ResourceManager could not load {description} from '{source}': {e}")
|
|
1184
|
+
|
|
1185
|
+
# Try direct file path
|
|
1186
|
+
try:
|
|
1187
|
+
if os.path.isfile(source):
|
|
1188
|
+
with open(source, 'r', encoding='utf-8') as f:
|
|
1189
|
+
content = f.read()
|
|
1190
|
+
logging.info(f"Loaded {description} from file path: {source}")
|
|
1191
|
+
return content
|
|
1192
|
+
except Exception as e:
|
|
1193
|
+
logging.debug(f"Could not load {description} from file path '{source}': {e}")
|
|
1194
|
+
|
|
1195
|
+
# Path-like source but couldn't load - log warning and return as-is
|
|
1196
|
+
logging.warning(f"Could not load {description} from path '{source}', using as inline text")
|
|
1157
1197
|
|
|
1158
|
-
#
|
|
1198
|
+
# Treat as inline text
|
|
1159
1199
|
logging.debug(f"Using inline text for {description}")
|
|
1160
1200
|
return source
|
|
1161
1201
|
|
|
@@ -1619,7 +1659,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
1619
1659
|
enable_filesystem_tools = Confirm.ask("Enable embedded filesystem tools?", default=False)
|
|
1620
1660
|
|
|
1621
1661
|
# Default values
|
|
1622
|
-
filesystem_allowed_path =
|
|
1662
|
+
filesystem_allowed_path = _DEFAULT_RUNNING_DIR
|
|
1623
1663
|
filesystem_access_mode = "read_write"
|
|
1624
1664
|
|
|
1625
1665
|
if enable_filesystem_tools:
|
|
@@ -1629,7 +1669,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
1629
1669
|
|
|
1630
1670
|
filesystem_allowed_path = Prompt.ask(
|
|
1631
1671
|
"Allowed directory path (tools can only access files within this directory)",
|
|
1632
|
-
default=
|
|
1672
|
+
default=_DEFAULT_RUNNING_DIR
|
|
1633
1673
|
)
|
|
1634
1674
|
|
|
1635
1675
|
# Access mode
|
|
@@ -1642,7 +1682,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
1642
1682
|
cli.console.print(" [2] Read/Write - Full access (read + write files, create directories)")
|
|
1643
1683
|
cli.console.print()
|
|
1644
1684
|
access_mode_choice = Prompt.ask(
|
|
1645
|
-
|
|
1685
|
+
_PROMPT_ACCESS_MODE,
|
|
1646
1686
|
choices=["1", "2"],
|
|
1647
1687
|
default="2"
|
|
1648
1688
|
)
|
|
@@ -1655,7 +1695,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
1655
1695
|
enable_document_tools = Confirm.ask("Enable embedded document tools (MS Office & PDF)?", default=False)
|
|
1656
1696
|
|
|
1657
1697
|
# Default values
|
|
1658
|
-
document_allowed_path =
|
|
1698
|
+
document_allowed_path = _DEFAULT_RUNNING_DIR
|
|
1659
1699
|
document_access_mode = "read"
|
|
1660
1700
|
document_max_file_size = "50"
|
|
1661
1701
|
document_max_pdf_pages = "100"
|
|
@@ -1670,7 +1710,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
1670
1710
|
|
|
1671
1711
|
document_allowed_path = Prompt.ask(
|
|
1672
1712
|
"Allowed directory path for documents",
|
|
1673
|
-
default=
|
|
1713
|
+
default=_DEFAULT_RUNNING_DIR
|
|
1674
1714
|
)
|
|
1675
1715
|
|
|
1676
1716
|
# Access mode
|
|
@@ -1683,7 +1723,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
1683
1723
|
cli.console.print(" [2] Read/Write - Read and create documents")
|
|
1684
1724
|
cli.console.print()
|
|
1685
1725
|
doc_access_mode_choice = Prompt.ask(
|
|
1686
|
-
|
|
1726
|
+
_PROMPT_ACCESS_MODE,
|
|
1687
1727
|
choices=["1", "2"],
|
|
1688
1728
|
default="1"
|
|
1689
1729
|
)
|
|
@@ -1723,7 +1763,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
1723
1763
|
enable_archive_tools = Confirm.ask("Enable embedded archive tools (ZIP, TAR)?", default=False)
|
|
1724
1764
|
|
|
1725
1765
|
# Default values
|
|
1726
|
-
archive_allowed_path =
|
|
1766
|
+
archive_allowed_path = _DEFAULT_RUNNING_DIR
|
|
1727
1767
|
archive_access_mode = "read"
|
|
1728
1768
|
archive_max_file_size = "100"
|
|
1729
1769
|
archive_max_files_to_list = "1000"
|
|
@@ -1735,7 +1775,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
1735
1775
|
|
|
1736
1776
|
archive_allowed_path = Prompt.ask(
|
|
1737
1777
|
"Allowed directory path for archives",
|
|
1738
|
-
default=
|
|
1778
|
+
default=_DEFAULT_RUNNING_DIR
|
|
1739
1779
|
)
|
|
1740
1780
|
|
|
1741
1781
|
# Access mode
|
|
@@ -1748,7 +1788,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
1748
1788
|
cli.console.print(" [2] Read/Write - Read and extract archives to disk")
|
|
1749
1789
|
cli.console.print()
|
|
1750
1790
|
archive_access_mode_choice = Prompt.ask(
|
|
1751
|
-
|
|
1791
|
+
_PROMPT_ACCESS_MODE,
|
|
1752
1792
|
choices=["1", "2"],
|
|
1753
1793
|
default="1"
|
|
1754
1794
|
)
|
|
@@ -2192,14 +2232,14 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
2192
2232
|
if document_templates_path:
|
|
2193
2233
|
escaped_templates_path = document_templates_path.replace('\\', '/')
|
|
2194
2234
|
config_content = re.sub(
|
|
2195
|
-
r'(templates_path:\s+)(
|
|
2235
|
+
r'(templates_path:\s+)([^\s#]+)',
|
|
2196
2236
|
f'\\g<1>{escaped_templates_path}',
|
|
2197
2237
|
config_content
|
|
2198
2238
|
)
|
|
2199
2239
|
# Default author (if provided)
|
|
2200
2240
|
if document_default_author:
|
|
2201
2241
|
config_content = re.sub(
|
|
2202
|
-
r'(default_author:\s+)(
|
|
2242
|
+
r'(default_author:\s+)([^\s#]+)',
|
|
2203
2243
|
f'\\g<1>{document_default_author}',
|
|
2204
2244
|
config_content
|
|
2205
2245
|
)
|
|
@@ -2358,9 +2398,9 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
2358
2398
|
def regather_and_display_costs(self):
|
|
2359
2399
|
"""Re-gather AWS Bedrock cost information and display it."""
|
|
2360
2400
|
# Check if cost tracking is enabled (new path with legacy fallback)
|
|
2361
|
-
cost_tracking_enabled = self._get_nested_setting(
|
|
2401
|
+
cost_tracking_enabled = self._get_nested_setting(_SETTING_BEDROCK_COST_TRACKING, None)
|
|
2362
2402
|
if cost_tracking_enabled is None:
|
|
2363
|
-
cost_tracking_enabled = self.settings.get(
|
|
2403
|
+
cost_tracking_enabled = self.settings.get(_SETTING_COST_TRACKING, False)
|
|
2364
2404
|
if not cost_tracking_enabled:
|
|
2365
2405
|
self.cli.print_warning("Cost tracking is disabled in configuration")
|
|
2366
2406
|
return
|
|
@@ -2729,7 +2769,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
2729
2769
|
# Step 1: Select model (will be used for both creation and execution)
|
|
2730
2770
|
models = self.llm_manager.list_all_models()
|
|
2731
2771
|
if not models:
|
|
2732
|
-
self.cli.print_error(
|
|
2772
|
+
self.cli.print_error(_MSG_NO_MODELS)
|
|
2733
2773
|
return
|
|
2734
2774
|
|
|
2735
2775
|
self.cli.console.print("\n[bold cyan]Select Model[/bold cyan]")
|
|
@@ -2923,7 +2963,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
2923
2963
|
progress.update(task, advance=100)
|
|
2924
2964
|
|
|
2925
2965
|
if not models:
|
|
2926
|
-
self.cli.print_error(
|
|
2966
|
+
self.cli.print_error(_MSG_NO_MODELS)
|
|
2927
2967
|
return None
|
|
2928
2968
|
|
|
2929
2969
|
model_id = self.cli.display_models(models)
|
|
@@ -3204,7 +3244,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
3204
3244
|
# Check if conversation is predefined - if so, block file deletion
|
|
3205
3245
|
if self.database.is_conversation_predefined(self.conversation_manager.current_conversation_id):
|
|
3206
3246
|
self.cli.print_error("Cannot delete files from predefined conversations")
|
|
3207
|
-
self.cli.print_info(
|
|
3247
|
+
self.cli.print_info(_MSG_MANAGED_CONVERSATION)
|
|
3208
3248
|
self.cli.wait_for_enter()
|
|
3209
3249
|
continue
|
|
3210
3250
|
|
|
@@ -3228,7 +3268,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
3228
3268
|
file_ids_input = self.cli.get_input("File IDs to delete").strip()
|
|
3229
3269
|
|
|
3230
3270
|
if not file_ids_input:
|
|
3231
|
-
self.cli.print_info(
|
|
3271
|
+
self.cli.print_info(_MSG_DELETE_CANCELLED)
|
|
3232
3272
|
self.cli.wait_for_enter()
|
|
3233
3273
|
continue
|
|
3234
3274
|
|
|
@@ -3248,7 +3288,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
3248
3288
|
else:
|
|
3249
3289
|
self.cli.print_error("Failed to delete files")
|
|
3250
3290
|
else:
|
|
3251
|
-
self.cli.print_info(
|
|
3291
|
+
self.cli.print_info(_MSG_DELETE_CANCELLED)
|
|
3252
3292
|
else:
|
|
3253
3293
|
# Parse comma-separated IDs
|
|
3254
3294
|
try:
|
|
@@ -3278,7 +3318,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
3278
3318
|
if failed_ids:
|
|
3279
3319
|
self.cli.print_error(f"Failed to delete files with IDs: {', '.join(map(str, failed_ids))}")
|
|
3280
3320
|
else:
|
|
3281
|
-
self.cli.print_info(
|
|
3321
|
+
self.cli.print_info(_MSG_DELETE_CANCELLED)
|
|
3282
3322
|
|
|
3283
3323
|
except ValueError:
|
|
3284
3324
|
self.cli.print_error("Invalid file IDs. Please enter comma-separated numbers or 'all'")
|
|
@@ -3290,7 +3330,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
3290
3330
|
# Check if conversation is predefined - if so, block model changes
|
|
3291
3331
|
if self.database.is_conversation_predefined(self.conversation_manager.current_conversation_id):
|
|
3292
3332
|
self.cli.print_error("Cannot change model for predefined conversations")
|
|
3293
|
-
self.cli.print_info(
|
|
3333
|
+
self.cli.print_info(_MSG_MANAGED_CONVERSATION)
|
|
3294
3334
|
self.cli.wait_for_enter()
|
|
3295
3335
|
continue
|
|
3296
3336
|
|
|
@@ -3308,7 +3348,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
3308
3348
|
progress.update(task, advance=100)
|
|
3309
3349
|
|
|
3310
3350
|
if not models:
|
|
3311
|
-
self.cli.print_error(
|
|
3351
|
+
self.cli.print_error(_MSG_NO_MODELS)
|
|
3312
3352
|
self.cli.wait_for_enter()
|
|
3313
3353
|
continue
|
|
3314
3354
|
|
|
@@ -3355,7 +3395,7 @@ class AWSBedrockCLI(AbstractApp):
|
|
|
3355
3395
|
# Check if conversation is predefined - if so, block instruction changes
|
|
3356
3396
|
if self.database.is_conversation_predefined(self.conversation_manager.current_conversation_id):
|
|
3357
3397
|
self.cli.print_error("Cannot change instructions for predefined conversations")
|
|
3358
|
-
self.cli.print_info(
|
|
3398
|
+
self.cli.print_info(_MSG_MANAGED_CONVERSATION)
|
|
3359
3399
|
self.cli.wait_for_enter()
|
|
3360
3400
|
continue
|
|
3361
3401
|
|