dtSpark 1.1.0a3__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 +112 -91
- 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 +8 -6
- dtSpark/web/endpoints/conversations.py +11 -9
- 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/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 +10 -10
- dtSpark/web/templates/conversations.html +2 -2
- dtSpark/web/templates/goodbye.html +2 -2
- dtSpark/web/templates/main_menu.html +17 -17
- dtSpark/web/web_interface.py +2 -2
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a6.dist-info}/METADATA +9 -2
- dtspark-1.1.0a6.dist-info/RECORD +96 -0
- dtspark-1.1.0a3.dist-info/RECORD +0 -96
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a6.dist-info}/WHEEL +0 -0
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a6.dist-info}/entry_points.txt +0 -0
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a6.dist-info}/licenses/LICENSE +0 -0
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a6.dist-info}/top_level.txt +0 -0
dtSpark/aws/pricing.py
CHANGED
|
@@ -15,6 +15,13 @@ from datetime import datetime, timedelta
|
|
|
15
15
|
from typing import Dict, Optional, Tuple
|
|
16
16
|
from botocore.exceptions import ClientError
|
|
17
17
|
|
|
18
|
+
# Model ID constants
|
|
19
|
+
_MODEL_CLAUDE_35_SONNET_V2 = 'anthropic.claude-3-5-sonnet-20241022-v2:0'
|
|
20
|
+
_MODEL_CLAUDE_35_SONNET_V1 = 'anthropic.claude-3-5-sonnet-20240620-v1:0'
|
|
21
|
+
_MODEL_CLAUDE_3_OPUS = 'anthropic.claude-3-opus-20240229-v1:0'
|
|
22
|
+
_MODEL_CLAUDE_3_SONNET = 'anthropic.claude-3-sonnet-20240229-v1:0'
|
|
23
|
+
_MODEL_CLAUDE_3_HAIKU = 'anthropic.claude-3-haiku-20240307-v1:0'
|
|
24
|
+
|
|
18
25
|
|
|
19
26
|
class BedrockPricing:
|
|
20
27
|
"""Manages AWS Bedrock pricing data and cost calculations."""
|
|
@@ -92,7 +99,7 @@ class BedrockPricing:
|
|
|
92
99
|
# Fall back to hardcoded pricing
|
|
93
100
|
logging.warning("All pricing fetch methods failed, using fallback pricing")
|
|
94
101
|
self._use_fallback_pricing()
|
|
95
|
-
return
|
|
102
|
+
return False
|
|
96
103
|
|
|
97
104
|
def _fetch_from_bulk_api(self) -> bool:
|
|
98
105
|
"""
|
|
@@ -163,7 +170,6 @@ class BedrockPricing:
|
|
|
163
170
|
service_codes = ['AmazonBedrockFoundationModels', 'AmazonBedrockService', 'AmazonBedrock']
|
|
164
171
|
|
|
165
172
|
all_price_lists = []
|
|
166
|
-
successful_service_code = None
|
|
167
173
|
|
|
168
174
|
for service_code in service_codes:
|
|
169
175
|
try:
|
|
@@ -176,7 +182,6 @@ class BedrockPricing:
|
|
|
176
182
|
price_list = response.get('PriceList', [])
|
|
177
183
|
if price_list:
|
|
178
184
|
all_price_lists.extend(price_list)
|
|
179
|
-
successful_service_code = service_code
|
|
180
185
|
logging.info(f"Found {len(price_list)} products with service code: {service_code}")
|
|
181
186
|
|
|
182
187
|
# Continue fetching if there are more results
|
|
@@ -359,15 +364,15 @@ class BedrockPricing:
|
|
|
359
364
|
elif 'sonnet 4' in model_lower or 'sonnet-4' in model_lower:
|
|
360
365
|
return 'anthropic.claude-sonnet-4-0-v1:0'
|
|
361
366
|
elif '3.5 sonnet v2' in model_lower or '3-5-sonnet-v2' in model_lower:
|
|
362
|
-
return
|
|
367
|
+
return _MODEL_CLAUDE_35_SONNET_V2
|
|
363
368
|
elif '3.5 sonnet' in model_lower or '3-5-sonnet' in model_lower:
|
|
364
|
-
return
|
|
369
|
+
return _MODEL_CLAUDE_35_SONNET_V1
|
|
365
370
|
elif '3 opus' in model_lower or '3-opus' in model_lower:
|
|
366
|
-
return
|
|
371
|
+
return _MODEL_CLAUDE_3_OPUS
|
|
367
372
|
elif '3 sonnet' in model_lower or '3-sonnet' in model_lower:
|
|
368
|
-
return
|
|
373
|
+
return _MODEL_CLAUDE_3_SONNET
|
|
369
374
|
elif '3 haiku' in model_lower or '3-haiku' in model_lower:
|
|
370
|
-
return
|
|
375
|
+
return _MODEL_CLAUDE_3_HAIKU
|
|
371
376
|
|
|
372
377
|
# Amazon Titan models
|
|
373
378
|
elif 'titan' in model_lower:
|
|
@@ -425,7 +430,6 @@ class BedrockPricing:
|
|
|
425
430
|
for term_key, term_value in on_demand.items():
|
|
426
431
|
price_dimensions = term_value.get('priceDimensions', {})
|
|
427
432
|
for dim_key, dim_value in price_dimensions.items():
|
|
428
|
-
unit = dim_value.get('unit', '')
|
|
429
433
|
price_per_unit = float(dim_value.get('pricePerUnit', {}).get('USD', 0))
|
|
430
434
|
|
|
431
435
|
# Determine if this is input or output pricing
|
|
@@ -484,26 +488,26 @@ class BedrockPricing:
|
|
|
484
488
|
# Fallback pricing for common models (prices per 1000 tokens)
|
|
485
489
|
fallback = {
|
|
486
490
|
# Claude 3.5 Sonnet v2
|
|
487
|
-
(
|
|
488
|
-
(
|
|
489
|
-
(
|
|
491
|
+
(_MODEL_CLAUDE_35_SONNET_V2, 'us-east-1'): {'input': 0.003, 'output': 0.015},
|
|
492
|
+
(_MODEL_CLAUDE_35_SONNET_V2, 'us-west-2'): {'input': 0.003, 'output': 0.015},
|
|
493
|
+
(_MODEL_CLAUDE_35_SONNET_V2, 'ap-southeast-2'): {'input': 0.003, 'output': 0.015},
|
|
490
494
|
|
|
491
495
|
# Claude 3.5 Sonnet v1
|
|
492
|
-
(
|
|
493
|
-
(
|
|
494
|
-
(
|
|
496
|
+
(_MODEL_CLAUDE_35_SONNET_V1, 'us-east-1'): {'input': 0.003, 'output': 0.015},
|
|
497
|
+
(_MODEL_CLAUDE_35_SONNET_V1, 'us-west-2'): {'input': 0.003, 'output': 0.015},
|
|
498
|
+
(_MODEL_CLAUDE_35_SONNET_V1, 'ap-southeast-2'): {'input': 0.003, 'output': 0.015},
|
|
495
499
|
|
|
496
500
|
# Claude 3 Opus
|
|
497
|
-
(
|
|
498
|
-
(
|
|
501
|
+
(_MODEL_CLAUDE_3_OPUS, 'us-east-1'): {'input': 0.015, 'output': 0.075},
|
|
502
|
+
(_MODEL_CLAUDE_3_OPUS, 'us-west-2'): {'input': 0.015, 'output': 0.075},
|
|
499
503
|
|
|
500
504
|
# Claude 3 Sonnet
|
|
501
|
-
(
|
|
502
|
-
(
|
|
505
|
+
(_MODEL_CLAUDE_3_SONNET, 'us-east-1'): {'input': 0.003, 'output': 0.015},
|
|
506
|
+
(_MODEL_CLAUDE_3_SONNET, 'us-west-2'): {'input': 0.003, 'output': 0.015},
|
|
503
507
|
|
|
504
508
|
# Claude 3 Haiku
|
|
505
|
-
(
|
|
506
|
-
(
|
|
509
|
+
(_MODEL_CLAUDE_3_HAIKU, 'us-east-1'): {'input': 0.00025, 'output': 0.00125},
|
|
510
|
+
(_MODEL_CLAUDE_3_HAIKU, 'us-west-2'): {'input': 0.00025, 'output': 0.00125},
|
|
507
511
|
}
|
|
508
512
|
|
|
509
513
|
self.pricing_data = fallback
|
dtSpark/cli_interface.py
CHANGED
|
@@ -27,6 +27,17 @@ import time
|
|
|
27
27
|
import re
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
# Common style and message string constants (SonarCloud S1192)
|
|
31
|
+
_STYLE_BOLD_CYAN = "bold cyan"
|
|
32
|
+
_STYLE_BOLD_YELLOW = "bold yellow"
|
|
33
|
+
_STYLE_BOLD_MAGENTA = "bold magenta"
|
|
34
|
+
_MSG_INVALID_SELECTION = "Invalid selection"
|
|
35
|
+
_MSG_CANCEL_OPTION = " [0] Cancel"
|
|
36
|
+
_MSG_ENTER_CHOICE = "Enter choice"
|
|
37
|
+
_MSG_INVALID_CHOICE = "Invalid choice"
|
|
38
|
+
_MSG_INVALID_INPUT = "Invalid input"
|
|
39
|
+
|
|
40
|
+
|
|
30
41
|
def extract_friendly_model_name(model_id: str) -> str:
|
|
31
42
|
"""
|
|
32
43
|
Extract a human-friendly model name from a full model ID or ARN.
|
|
@@ -221,9 +232,10 @@ class CLIInterface:
|
|
|
221
232
|
self.running = True
|
|
222
233
|
self.model_changing_enabled = True # Can be disabled if model is locked via config
|
|
223
234
|
self.cost_tracking_enabled = False # Can be enabled via config
|
|
235
|
+
self.actions_enabled = False # Can be enabled via autonomous_actions.enabled config
|
|
224
236
|
self._active_status_indicator = None # Track active status indicator for pause/resume
|
|
225
237
|
|
|
226
|
-
def print_splash_screen(self, full_name: str, description: str, version: str):
|
|
238
|
+
def print_splash_screen(self, full_name: str, description: str, version: str): # noqa: S1172
|
|
227
239
|
"""
|
|
228
240
|
Print application splash screen with SPARK branding.
|
|
229
241
|
|
|
@@ -286,7 +298,7 @@ class CLIInterface:
|
|
|
286
298
|
# This is now replaced by print_splash_screen
|
|
287
299
|
pass
|
|
288
300
|
|
|
289
|
-
def create_progress(self, description: str = "Initialising...") -> Progress:
|
|
301
|
+
def create_progress(self, description: str = "Initialising...") -> Progress: # noqa: S1172
|
|
290
302
|
"""
|
|
291
303
|
Create a progress bar for tracking operations.
|
|
292
304
|
|
|
@@ -385,12 +397,13 @@ class CLIInterface:
|
|
|
385
397
|
choice_map[str(option_num)] = 'list'
|
|
386
398
|
option_num += 1
|
|
387
399
|
|
|
388
|
-
# Manage Autonomous Actions
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
400
|
+
# Manage Autonomous Actions (only when enabled)
|
|
401
|
+
if self.actions_enabled:
|
|
402
|
+
menu_content.append(" ", style="")
|
|
403
|
+
menu_content.append(str(option_num), style="cyan")
|
|
404
|
+
menu_content.append(". Manage Autonomous Actions\n", style="")
|
|
405
|
+
choice_map[str(option_num)] = 'autonomous'
|
|
406
|
+
option_num += 1
|
|
394
407
|
|
|
395
408
|
# Quit
|
|
396
409
|
menu_content.append(" ", style="")
|
|
@@ -402,7 +415,7 @@ class CLIInterface:
|
|
|
402
415
|
menu_panel = Panel(
|
|
403
416
|
menu_content,
|
|
404
417
|
title="[bold bright_magenta]MAIN MENU[/bold bright_magenta]",
|
|
405
|
-
border_style=
|
|
418
|
+
border_style=_STYLE_BOLD_CYAN,
|
|
406
419
|
box=box.HEAVY,
|
|
407
420
|
padding=(0, 1)
|
|
408
421
|
)
|
|
@@ -562,7 +575,7 @@ class CLIInterface:
|
|
|
562
575
|
"""
|
|
563
576
|
# Create table
|
|
564
577
|
table = Table(show_header=False, box=box.ROUNDED, border_style="cyan")
|
|
565
|
-
table.add_column("No.", style=
|
|
578
|
+
table.add_column("No.", style=_STYLE_BOLD_YELLOW, width=4)
|
|
566
579
|
table.add_column("Option", style="white")
|
|
567
580
|
|
|
568
581
|
for i, option in enumerate(options, 1):
|
|
@@ -587,7 +600,7 @@ class CLIInterface:
|
|
|
587
600
|
elif choice == len(options) + 1:
|
|
588
601
|
return -1
|
|
589
602
|
else:
|
|
590
|
-
self.print_error(
|
|
603
|
+
self.print_error(_MSG_INVALID_SELECTION)
|
|
591
604
|
return -1
|
|
592
605
|
except ValueError:
|
|
593
606
|
self.print_error("Please enter a valid number")
|
|
@@ -612,7 +625,7 @@ class CLIInterface:
|
|
|
612
625
|
|
|
613
626
|
self.console.print()
|
|
614
627
|
self.print_separator("─")
|
|
615
|
-
self.console.print(
|
|
628
|
+
self.console.print("\n[bold yellow]🔐 Tool Permission Request[/bold yellow]")
|
|
616
629
|
self.console.print(f"\nThe assistant wants to use the tool: [bold cyan]{tool_name}[/bold cyan]")
|
|
617
630
|
|
|
618
631
|
if tool_description:
|
|
@@ -665,11 +678,11 @@ class CLIInterface:
|
|
|
665
678
|
# Create table
|
|
666
679
|
table = Table(
|
|
667
680
|
show_header=True,
|
|
668
|
-
header_style=
|
|
681
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
669
682
|
box=box.ROUNDED,
|
|
670
683
|
border_style="cyan"
|
|
671
684
|
)
|
|
672
|
-
table.add_column("No.", style=
|
|
685
|
+
table.add_column("No.", style=_STYLE_BOLD_YELLOW, width=4)
|
|
673
686
|
table.add_column("Model Name", style="cyan")
|
|
674
687
|
table.add_column("Provider", style="green")
|
|
675
688
|
table.add_column("Access Method", style="magenta")
|
|
@@ -716,7 +729,7 @@ class CLIInterface:
|
|
|
716
729
|
if 1 <= choice <= len(models):
|
|
717
730
|
return models[choice - 1]['id']
|
|
718
731
|
else:
|
|
719
|
-
self.print_error(
|
|
732
|
+
self.print_error(_MSG_INVALID_SELECTION)
|
|
720
733
|
return None
|
|
721
734
|
except ValueError:
|
|
722
735
|
self.print_error("Please enter a valid number or Q to quit")
|
|
@@ -739,11 +752,11 @@ class CLIInterface:
|
|
|
739
752
|
# Create table
|
|
740
753
|
table = Table(
|
|
741
754
|
show_header=True,
|
|
742
|
-
header_style=
|
|
755
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
743
756
|
box=box.ROUNDED,
|
|
744
757
|
border_style="cyan"
|
|
745
758
|
)
|
|
746
|
-
table.add_column("No.", style=
|
|
759
|
+
table.add_column("No.", style=_STYLE_BOLD_YELLOW, width=4)
|
|
747
760
|
table.add_column("Name", style="cyan")
|
|
748
761
|
table.add_column("Model", style="green")
|
|
749
762
|
table.add_column("Created", style="blue")
|
|
@@ -789,7 +802,7 @@ class CLIInterface:
|
|
|
789
802
|
if 1 <= choice <= len(conversations):
|
|
790
803
|
return conversations[choice - 1]['id']
|
|
791
804
|
else:
|
|
792
|
-
self.print_error(
|
|
805
|
+
self.print_error(_MSG_INVALID_SELECTION)
|
|
793
806
|
return None
|
|
794
807
|
except ValueError:
|
|
795
808
|
self.print_error("Please enter a valid number or 'N' for new conversation")
|
|
@@ -847,7 +860,7 @@ class CLIInterface:
|
|
|
847
860
|
self.console.print()
|
|
848
861
|
self.console.print(Panel(
|
|
849
862
|
"[bold]Conversation History[/bold]",
|
|
850
|
-
style=
|
|
863
|
+
style=_STYLE_BOLD_MAGENTA,
|
|
851
864
|
box=box.DOUBLE
|
|
852
865
|
))
|
|
853
866
|
|
|
@@ -879,7 +892,7 @@ class CLIInterface:
|
|
|
879
892
|
|
|
880
893
|
# Create info table
|
|
881
894
|
table = Table(show_header=False, box=None, padding=(0, 2))
|
|
882
|
-
table.add_column("Label", style=
|
|
895
|
+
table.add_column("Label", style=_STYLE_BOLD_CYAN)
|
|
883
896
|
table.add_column("Value", style="white")
|
|
884
897
|
|
|
885
898
|
table.add_row("Conversation", conversation['name'])
|
|
@@ -900,12 +913,7 @@ class CLIInterface:
|
|
|
900
913
|
|
|
901
914
|
# Add instructions indicator
|
|
902
915
|
if conversation.get('instructions'):
|
|
903
|
-
|
|
904
|
-
# In detailed view, show YES and we'll display full instructions below
|
|
905
|
-
table.add_row("Instructions", "[green]YES[/green]")
|
|
906
|
-
else:
|
|
907
|
-
# In regular view, just show YES
|
|
908
|
-
table.add_row("Instructions", "[green]YES[/green]")
|
|
916
|
+
table.add_row("Instructions", "[green]YES[/green]")
|
|
909
917
|
else:
|
|
910
918
|
table.add_row("Instructions", "[dim]NO[/dim]")
|
|
911
919
|
|
|
@@ -1104,7 +1112,7 @@ class CLIInterface:
|
|
|
1104
1112
|
try:
|
|
1105
1113
|
from dtSpark import launch
|
|
1106
1114
|
version = launch.version()
|
|
1107
|
-
except:
|
|
1115
|
+
except ImportError:
|
|
1108
1116
|
version = "X.X"
|
|
1109
1117
|
|
|
1110
1118
|
# Get log path
|
|
@@ -1171,7 +1179,7 @@ class CLIInterface:
|
|
|
1171
1179
|
# Create table for server details
|
|
1172
1180
|
table = Table(
|
|
1173
1181
|
show_header=True,
|
|
1174
|
-
header_style=
|
|
1182
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1175
1183
|
box=box.ROUNDED,
|
|
1176
1184
|
border_style="green"
|
|
1177
1185
|
)
|
|
@@ -1345,7 +1353,7 @@ class CLIInterface:
|
|
|
1345
1353
|
# Budget section
|
|
1346
1354
|
if budget_limit > 0:
|
|
1347
1355
|
content_parts.append("")
|
|
1348
|
-
content_parts.append(
|
|
1356
|
+
content_parts.append("[bold cyan]Budget Status:[/bold cyan]")
|
|
1349
1357
|
content_parts.append(f" • Budget Limit: [yellow]${budget_limit:.2f} USD[/yellow]")
|
|
1350
1358
|
|
|
1351
1359
|
if budget_exceeded:
|
|
@@ -1473,7 +1481,7 @@ class CLIInterface:
|
|
|
1473
1481
|
f"[dim]({input_str})[/dim]"
|
|
1474
1482
|
)
|
|
1475
1483
|
|
|
1476
|
-
def display_tool_result(self, tool_name: str, result: str, is_error: bool = False):
|
|
1484
|
+
def display_tool_result(self, tool_name: str, result: str, is_error: bool = False): # noqa: S1172
|
|
1477
1485
|
"""
|
|
1478
1486
|
Display a tool result during chat.
|
|
1479
1487
|
|
|
@@ -1555,7 +1563,7 @@ class CLIInterface:
|
|
|
1555
1563
|
found_files = FileManager.scan_directory(str(path.absolute()), recursive=recursive)
|
|
1556
1564
|
|
|
1557
1565
|
if not found_files:
|
|
1558
|
-
self.print_warning(
|
|
1566
|
+
self.print_warning(" No supported files found in directory")
|
|
1559
1567
|
continue
|
|
1560
1568
|
|
|
1561
1569
|
self.print_success(f" Found {len(found_files)} supported file(s)")
|
|
@@ -1605,7 +1613,6 @@ class CLIInterface:
|
|
|
1605
1613
|
|
|
1606
1614
|
else:
|
|
1607
1615
|
self.print_error(f"Invalid path type: {input_path}")
|
|
1608
|
-
continue
|
|
1609
1616
|
|
|
1610
1617
|
if file_attachments:
|
|
1611
1618
|
self.console.print()
|
|
@@ -1636,7 +1643,7 @@ class CLIInterface:
|
|
|
1636
1643
|
# Create table for attached files
|
|
1637
1644
|
table = Table(
|
|
1638
1645
|
show_header=True,
|
|
1639
|
-
header_style=
|
|
1646
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1640
1647
|
box=box.ROUNDED,
|
|
1641
1648
|
border_style="blue"
|
|
1642
1649
|
)
|
|
@@ -1700,7 +1707,7 @@ class CLIInterface:
|
|
|
1700
1707
|
# Create table for transactions
|
|
1701
1708
|
table = Table(
|
|
1702
1709
|
show_header=True,
|
|
1703
|
-
header_style=
|
|
1710
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1704
1711
|
box=box.ROUNDED,
|
|
1705
1712
|
border_style="yellow"
|
|
1706
1713
|
)
|
|
@@ -1746,7 +1753,7 @@ class CLIInterface:
|
|
|
1746
1753
|
|
|
1747
1754
|
# Create details table
|
|
1748
1755
|
details_table = Table(show_header=False, box=None, padding=(0, 2))
|
|
1749
|
-
details_table.add_column("Label", style=
|
|
1756
|
+
details_table.add_column("Label", style=_STYLE_BOLD_YELLOW)
|
|
1750
1757
|
details_table.add_column("Value", style="white")
|
|
1751
1758
|
|
|
1752
1759
|
timestamp = datetime.fromisoformat(transaction['transaction_timestamp'])
|
|
@@ -1781,7 +1788,7 @@ class CLIInterface:
|
|
|
1781
1788
|
self.console.print()
|
|
1782
1789
|
try:
|
|
1783
1790
|
input_formatted = json.dumps(json.loads(transaction['tool_input']), indent=2)
|
|
1784
|
-
except:
|
|
1791
|
+
except ValueError:
|
|
1785
1792
|
input_formatted = transaction['tool_input']
|
|
1786
1793
|
|
|
1787
1794
|
self.console.print(Panel(
|
|
@@ -1812,7 +1819,7 @@ class CLIInterface:
|
|
|
1812
1819
|
"""
|
|
1813
1820
|
# Create stats table
|
|
1814
1821
|
stats_table = Table(show_header=False, box=None, padding=(0, 2))
|
|
1815
|
-
stats_table.add_column("Metric", style=
|
|
1822
|
+
stats_table.add_column("Metric", style=_STYLE_BOLD_YELLOW)
|
|
1816
1823
|
stats_table.add_column("Value", style="white")
|
|
1817
1824
|
|
|
1818
1825
|
stats_table.add_row("Total Transactions", f"{stats['total_transactions']:,}")
|
|
@@ -1831,7 +1838,7 @@ class CLIInterface:
|
|
|
1831
1838
|
self.console.print()
|
|
1832
1839
|
tools_table = Table(
|
|
1833
1840
|
show_header=True,
|
|
1834
|
-
header_style=
|
|
1841
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1835
1842
|
box=box.ROUNDED,
|
|
1836
1843
|
border_style="green"
|
|
1837
1844
|
)
|
|
@@ -1852,7 +1859,7 @@ class CLIInterface:
|
|
|
1852
1859
|
self.console.print()
|
|
1853
1860
|
conv_table = Table(
|
|
1854
1861
|
show_header=True,
|
|
1855
|
-
header_style=
|
|
1862
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1856
1863
|
box=box.ROUNDED,
|
|
1857
1864
|
border_style="cyan"
|
|
1858
1865
|
)
|
|
@@ -1885,7 +1892,7 @@ class CLIInterface:
|
|
|
1885
1892
|
|
|
1886
1893
|
table = Table(
|
|
1887
1894
|
show_header=True,
|
|
1888
|
-
header_style=
|
|
1895
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1889
1896
|
box=box.ROUNDED,
|
|
1890
1897
|
border_style="cyan"
|
|
1891
1898
|
)
|
|
@@ -2046,9 +2053,9 @@ class CLIInterface:
|
|
|
2046
2053
|
for i, state in enumerate(server_states, 1):
|
|
2047
2054
|
status = "[green]enabled[/green]" if state['enabled'] else "[red]disabled[/red]"
|
|
2048
2055
|
self.console.print(f" [{i}] {state['server_name']} ({status})")
|
|
2049
|
-
self.console.print(
|
|
2056
|
+
self.console.print(_MSG_CANCEL_OPTION)
|
|
2050
2057
|
|
|
2051
|
-
choice = self.get_input(
|
|
2058
|
+
choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2052
2059
|
try:
|
|
2053
2060
|
idx = int(choice)
|
|
2054
2061
|
if idx == 0:
|
|
@@ -2056,10 +2063,10 @@ class CLIInterface:
|
|
|
2056
2063
|
if 1 <= idx <= len(server_states):
|
|
2057
2064
|
return server_states[idx - 1]['server_name']
|
|
2058
2065
|
else:
|
|
2059
|
-
self.print_error(
|
|
2066
|
+
self.print_error(_MSG_INVALID_CHOICE)
|
|
2060
2067
|
return None
|
|
2061
2068
|
except ValueError:
|
|
2062
|
-
self.print_error(
|
|
2069
|
+
self.print_error(_MSG_INVALID_INPUT)
|
|
2063
2070
|
return None
|
|
2064
2071
|
|
|
2065
2072
|
# =========================================================================
|
|
@@ -2103,7 +2110,7 @@ class CLIInterface:
|
|
|
2103
2110
|
menu_panel = Panel(
|
|
2104
2111
|
menu_content,
|
|
2105
2112
|
title="[bold bright_magenta]AUTONOMOUS ACTIONS[/bold bright_magenta]",
|
|
2106
|
-
border_style=
|
|
2113
|
+
border_style=_STYLE_BOLD_CYAN,
|
|
2107
2114
|
box=box.HEAVY,
|
|
2108
2115
|
padding=(0, 1)
|
|
2109
2116
|
)
|
|
@@ -2149,7 +2156,7 @@ class CLIInterface:
|
|
|
2149
2156
|
|
|
2150
2157
|
table = Table(
|
|
2151
2158
|
show_header=True,
|
|
2152
|
-
header_style=
|
|
2159
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
2153
2160
|
box=box.ROUNDED,
|
|
2154
2161
|
border_style="cyan"
|
|
2155
2162
|
)
|
|
@@ -2229,7 +2236,7 @@ class CLIInterface:
|
|
|
2229
2236
|
|
|
2230
2237
|
table = Table(
|
|
2231
2238
|
show_header=True,
|
|
2232
|
-
header_style=
|
|
2239
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
2233
2240
|
box=box.ROUNDED,
|
|
2234
2241
|
border_style="cyan"
|
|
2235
2242
|
)
|
|
@@ -2264,7 +2271,7 @@ class CLIInterface:
|
|
|
2264
2271
|
completed = datetime.fromisoformat(completed.replace('Z', '+00:00'))
|
|
2265
2272
|
duration = (completed - started).total_seconds()
|
|
2266
2273
|
duration_str = f"{duration:.1f}s"
|
|
2267
|
-
except:
|
|
2274
|
+
except (ValueError, TypeError):
|
|
2268
2275
|
duration_str = "N/A"
|
|
2269
2276
|
else:
|
|
2270
2277
|
duration_str = "N/A"
|
|
@@ -2347,9 +2354,9 @@ class CLIInterface:
|
|
|
2347
2354
|
for i, action in enumerate(actions, 1):
|
|
2348
2355
|
status = "[green]enabled[/green]" if action['is_enabled'] else "[red]disabled[/red]"
|
|
2349
2356
|
self.console.print(f" [{i}] {action['name']} ({status})")
|
|
2350
|
-
self.console.print(
|
|
2357
|
+
self.console.print(_MSG_CANCEL_OPTION)
|
|
2351
2358
|
|
|
2352
|
-
choice = self.get_input(
|
|
2359
|
+
choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2353
2360
|
try:
|
|
2354
2361
|
idx = int(choice)
|
|
2355
2362
|
if idx == 0:
|
|
@@ -2357,10 +2364,10 @@ class CLIInterface:
|
|
|
2357
2364
|
if 1 <= idx <= len(actions):
|
|
2358
2365
|
return actions[idx - 1]['id']
|
|
2359
2366
|
else:
|
|
2360
|
-
self.print_error(
|
|
2367
|
+
self.print_error(_MSG_INVALID_CHOICE)
|
|
2361
2368
|
return None
|
|
2362
2369
|
except ValueError:
|
|
2363
|
-
self.print_error(
|
|
2370
|
+
self.print_error(_MSG_INVALID_INPUT)
|
|
2364
2371
|
return None
|
|
2365
2372
|
|
|
2366
2373
|
def select_run(self, runs: List[Dict], prompt: str = "Select a run") -> Optional[int]:
|
|
@@ -2383,9 +2390,9 @@ class CLIInterface:
|
|
|
2383
2390
|
status = run.get('status', 'unknown')
|
|
2384
2391
|
started = str(run.get('started_at', ''))[:16]
|
|
2385
2392
|
self.console.print(f" [{i}] Run {run['id']} - {status} ({started})")
|
|
2386
|
-
self.console.print(
|
|
2393
|
+
self.console.print(_MSG_CANCEL_OPTION)
|
|
2387
2394
|
|
|
2388
|
-
choice = self.get_input(
|
|
2395
|
+
choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2389
2396
|
try:
|
|
2390
2397
|
idx = int(choice)
|
|
2391
2398
|
if idx == 0:
|
|
@@ -2393,10 +2400,10 @@ class CLIInterface:
|
|
|
2393
2400
|
if 1 <= idx <= len(runs):
|
|
2394
2401
|
return runs[idx - 1]['id']
|
|
2395
2402
|
else:
|
|
2396
|
-
self.print_error(
|
|
2403
|
+
self.print_error(_MSG_INVALID_CHOICE)
|
|
2397
2404
|
return None
|
|
2398
2405
|
except ValueError:
|
|
2399
|
-
self.print_error(
|
|
2406
|
+
self.print_error(_MSG_INVALID_INPUT)
|
|
2400
2407
|
return None
|
|
2401
2408
|
|
|
2402
2409
|
def select_export_format(self) -> Optional[str]:
|
|
@@ -2410,9 +2417,9 @@ class CLIInterface:
|
|
|
2410
2417
|
self.console.print(" [1] Plain Text")
|
|
2411
2418
|
self.console.print(" [2] HTML")
|
|
2412
2419
|
self.console.print(" [3] Markdown")
|
|
2413
|
-
self.console.print(
|
|
2420
|
+
self.console.print(_MSG_CANCEL_OPTION)
|
|
2414
2421
|
|
|
2415
|
-
choice = self.get_input(
|
|
2422
|
+
choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2416
2423
|
format_map = {'1': 'text', '2': 'html', '3': 'markdown'}
|
|
2417
2424
|
return format_map.get(choice)
|
|
2418
2425
|
|
|
@@ -2459,7 +2466,7 @@ class CLIInterface:
|
|
|
2459
2466
|
friendly_name = extract_friendly_model_name(model.get('id', ''))
|
|
2460
2467
|
self.console.print(f" [{i}] {friendly_name}")
|
|
2461
2468
|
|
|
2462
|
-
model_choice = self.get_input(
|
|
2469
|
+
model_choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2463
2470
|
try:
|
|
2464
2471
|
model_idx = int(model_choice) - 1
|
|
2465
2472
|
if model_idx < 0 or model_idx >= len(available_models):
|
|
@@ -2467,7 +2474,7 @@ class CLIInterface:
|
|
|
2467
2474
|
return None
|
|
2468
2475
|
model_id = available_models[model_idx]['id']
|
|
2469
2476
|
except ValueError:
|
|
2470
|
-
self.print_error(
|
|
2477
|
+
self.print_error(_MSG_INVALID_INPUT)
|
|
2471
2478
|
return None
|
|
2472
2479
|
|
|
2473
2480
|
# Step 5: Schedule type
|
|
@@ -2475,7 +2482,7 @@ class CLIInterface:
|
|
|
2475
2482
|
self.console.print(" [1] One-off (run once at specific time)")
|
|
2476
2483
|
self.console.print(" [2] Recurring (run on schedule)")
|
|
2477
2484
|
|
|
2478
|
-
schedule_choice = self.get_input(
|
|
2485
|
+
schedule_choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2479
2486
|
if schedule_choice == '1':
|
|
2480
2487
|
schedule_type = 'one_off'
|
|
2481
2488
|
self.console.print("\n[dim]Enter date/time in format: YYYY-MM-DD HH:MM[/dim]")
|
|
@@ -2504,7 +2511,7 @@ class CLIInterface:
|
|
|
2504
2511
|
self.console.print(" [1] Fresh - Start with clean context each run")
|
|
2505
2512
|
self.console.print(" [2] Cumulative - Carry context from previous runs")
|
|
2506
2513
|
|
|
2507
|
-
context_choice = self.get_input(
|
|
2514
|
+
context_choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2508
2515
|
context_mode = 'cumulative' if context_choice == '2' else 'fresh'
|
|
2509
2516
|
|
|
2510
2517
|
# Step 7: Max failures
|