dtSpark 1.1.0a3__py3-none-any.whl → 1.1.0a7__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 +77 -68
- dtSpark/conversation_manager.py +54 -47
- dtSpark/core/application.py +114 -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 +11 -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 +18 -9
- dtSpark/web/endpoints/main_menu.py +132 -105
- dtSpark/web/endpoints/streaming.py +2 -2
- dtSpark/web/server.py +70 -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 +15 -0
- dtSpark/web/templates/chat.html +10 -10
- dtSpark/web/templates/conversations.html +6 -2
- dtSpark/web/templates/goodbye.html +2 -2
- dtSpark/web/templates/main_menu.html +19 -17
- dtSpark/web/web_interface.py +2 -2
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a7.dist-info}/METADATA +9 -2
- dtspark-1.1.0a7.dist-info/RECORD +96 -0
- dtspark-1.1.0a3.dist-info/RECORD +0 -96
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a7.dist-info}/WHEEL +0 -0
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a7.dist-info}/entry_points.txt +0 -0
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a7.dist-info}/licenses/LICENSE +0 -0
- {dtspark-1.1.0a3.dist-info → dtspark-1.1.0a7.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,11 @@ 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
|
|
236
|
+
self.new_conversations_allowed = True # Can be disabled via predefined_conversations.allow_new_conversations
|
|
224
237
|
self._active_status_indicator = None # Track active status indicator for pause/resume
|
|
225
238
|
|
|
226
|
-
def print_splash_screen(self, full_name: str, description: str, version: str):
|
|
239
|
+
def print_splash_screen(self, full_name: str, description: str, version: str): # noqa: S1172
|
|
227
240
|
"""
|
|
228
241
|
Print application splash screen with SPARK branding.
|
|
229
242
|
|
|
@@ -286,7 +299,7 @@ class CLIInterface:
|
|
|
286
299
|
# This is now replaced by print_splash_screen
|
|
287
300
|
pass
|
|
288
301
|
|
|
289
|
-
def create_progress(self, description: str = "Initialising...") -> Progress:
|
|
302
|
+
def create_progress(self, description: str = "Initialising...") -> Progress: # noqa: S1172
|
|
290
303
|
"""
|
|
291
304
|
Create a progress bar for tracking operations.
|
|
292
305
|
|
|
@@ -371,12 +384,13 @@ class CLIInterface:
|
|
|
371
384
|
choice_map[str(option_num)] = 'costs'
|
|
372
385
|
option_num += 1
|
|
373
386
|
|
|
374
|
-
# Start New Conversation
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
387
|
+
# Start New Conversation (only when new conversations are allowed)
|
|
388
|
+
if self.new_conversations_allowed:
|
|
389
|
+
menu_content.append(" ", style="")
|
|
390
|
+
menu_content.append(str(option_num), style="cyan")
|
|
391
|
+
menu_content.append(". Start New Conversation\n", style="")
|
|
392
|
+
choice_map[str(option_num)] = 'new'
|
|
393
|
+
option_num += 1
|
|
380
394
|
|
|
381
395
|
# List and Select Conversation
|
|
382
396
|
menu_content.append(" ", style="")
|
|
@@ -385,12 +399,13 @@ class CLIInterface:
|
|
|
385
399
|
choice_map[str(option_num)] = 'list'
|
|
386
400
|
option_num += 1
|
|
387
401
|
|
|
388
|
-
# Manage Autonomous Actions
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
402
|
+
# Manage Autonomous Actions (only when enabled)
|
|
403
|
+
if self.actions_enabled:
|
|
404
|
+
menu_content.append(" ", style="")
|
|
405
|
+
menu_content.append(str(option_num), style="cyan")
|
|
406
|
+
menu_content.append(". Manage Autonomous Actions\n", style="")
|
|
407
|
+
choice_map[str(option_num)] = 'autonomous'
|
|
408
|
+
option_num += 1
|
|
394
409
|
|
|
395
410
|
# Quit
|
|
396
411
|
menu_content.append(" ", style="")
|
|
@@ -402,7 +417,7 @@ class CLIInterface:
|
|
|
402
417
|
menu_panel = Panel(
|
|
403
418
|
menu_content,
|
|
404
419
|
title="[bold bright_magenta]MAIN MENU[/bold bright_magenta]",
|
|
405
|
-
border_style=
|
|
420
|
+
border_style=_STYLE_BOLD_CYAN,
|
|
406
421
|
box=box.HEAVY,
|
|
407
422
|
padding=(0, 1)
|
|
408
423
|
)
|
|
@@ -562,7 +577,7 @@ class CLIInterface:
|
|
|
562
577
|
"""
|
|
563
578
|
# Create table
|
|
564
579
|
table = Table(show_header=False, box=box.ROUNDED, border_style="cyan")
|
|
565
|
-
table.add_column("No.", style=
|
|
580
|
+
table.add_column("No.", style=_STYLE_BOLD_YELLOW, width=4)
|
|
566
581
|
table.add_column("Option", style="white")
|
|
567
582
|
|
|
568
583
|
for i, option in enumerate(options, 1):
|
|
@@ -587,7 +602,7 @@ class CLIInterface:
|
|
|
587
602
|
elif choice == len(options) + 1:
|
|
588
603
|
return -1
|
|
589
604
|
else:
|
|
590
|
-
self.print_error(
|
|
605
|
+
self.print_error(_MSG_INVALID_SELECTION)
|
|
591
606
|
return -1
|
|
592
607
|
except ValueError:
|
|
593
608
|
self.print_error("Please enter a valid number")
|
|
@@ -612,7 +627,7 @@ class CLIInterface:
|
|
|
612
627
|
|
|
613
628
|
self.console.print()
|
|
614
629
|
self.print_separator("─")
|
|
615
|
-
self.console.print(
|
|
630
|
+
self.console.print("\n[bold yellow]🔐 Tool Permission Request[/bold yellow]")
|
|
616
631
|
self.console.print(f"\nThe assistant wants to use the tool: [bold cyan]{tool_name}[/bold cyan]")
|
|
617
632
|
|
|
618
633
|
if tool_description:
|
|
@@ -665,11 +680,11 @@ class CLIInterface:
|
|
|
665
680
|
# Create table
|
|
666
681
|
table = Table(
|
|
667
682
|
show_header=True,
|
|
668
|
-
header_style=
|
|
683
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
669
684
|
box=box.ROUNDED,
|
|
670
685
|
border_style="cyan"
|
|
671
686
|
)
|
|
672
|
-
table.add_column("No.", style=
|
|
687
|
+
table.add_column("No.", style=_STYLE_BOLD_YELLOW, width=4)
|
|
673
688
|
table.add_column("Model Name", style="cyan")
|
|
674
689
|
table.add_column("Provider", style="green")
|
|
675
690
|
table.add_column("Access Method", style="magenta")
|
|
@@ -716,7 +731,7 @@ class CLIInterface:
|
|
|
716
731
|
if 1 <= choice <= len(models):
|
|
717
732
|
return models[choice - 1]['id']
|
|
718
733
|
else:
|
|
719
|
-
self.print_error(
|
|
734
|
+
self.print_error(_MSG_INVALID_SELECTION)
|
|
720
735
|
return None
|
|
721
736
|
except ValueError:
|
|
722
737
|
self.print_error("Please enter a valid number or Q to quit")
|
|
@@ -739,11 +754,11 @@ class CLIInterface:
|
|
|
739
754
|
# Create table
|
|
740
755
|
table = Table(
|
|
741
756
|
show_header=True,
|
|
742
|
-
header_style=
|
|
757
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
743
758
|
box=box.ROUNDED,
|
|
744
759
|
border_style="cyan"
|
|
745
760
|
)
|
|
746
|
-
table.add_column("No.", style=
|
|
761
|
+
table.add_column("No.", style=_STYLE_BOLD_YELLOW, width=4)
|
|
747
762
|
table.add_column("Name", style="cyan")
|
|
748
763
|
table.add_column("Model", style="green")
|
|
749
764
|
table.add_column("Created", style="blue")
|
|
@@ -789,7 +804,7 @@ class CLIInterface:
|
|
|
789
804
|
if 1 <= choice <= len(conversations):
|
|
790
805
|
return conversations[choice - 1]['id']
|
|
791
806
|
else:
|
|
792
|
-
self.print_error(
|
|
807
|
+
self.print_error(_MSG_INVALID_SELECTION)
|
|
793
808
|
return None
|
|
794
809
|
except ValueError:
|
|
795
810
|
self.print_error("Please enter a valid number or 'N' for new conversation")
|
|
@@ -847,7 +862,7 @@ class CLIInterface:
|
|
|
847
862
|
self.console.print()
|
|
848
863
|
self.console.print(Panel(
|
|
849
864
|
"[bold]Conversation History[/bold]",
|
|
850
|
-
style=
|
|
865
|
+
style=_STYLE_BOLD_MAGENTA,
|
|
851
866
|
box=box.DOUBLE
|
|
852
867
|
))
|
|
853
868
|
|
|
@@ -879,7 +894,7 @@ class CLIInterface:
|
|
|
879
894
|
|
|
880
895
|
# Create info table
|
|
881
896
|
table = Table(show_header=False, box=None, padding=(0, 2))
|
|
882
|
-
table.add_column("Label", style=
|
|
897
|
+
table.add_column("Label", style=_STYLE_BOLD_CYAN)
|
|
883
898
|
table.add_column("Value", style="white")
|
|
884
899
|
|
|
885
900
|
table.add_row("Conversation", conversation['name'])
|
|
@@ -900,12 +915,7 @@ class CLIInterface:
|
|
|
900
915
|
|
|
901
916
|
# Add instructions indicator
|
|
902
917
|
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]")
|
|
918
|
+
table.add_row("Instructions", "[green]YES[/green]")
|
|
909
919
|
else:
|
|
910
920
|
table.add_row("Instructions", "[dim]NO[/dim]")
|
|
911
921
|
|
|
@@ -1104,7 +1114,7 @@ class CLIInterface:
|
|
|
1104
1114
|
try:
|
|
1105
1115
|
from dtSpark import launch
|
|
1106
1116
|
version = launch.version()
|
|
1107
|
-
except:
|
|
1117
|
+
except ImportError:
|
|
1108
1118
|
version = "X.X"
|
|
1109
1119
|
|
|
1110
1120
|
# Get log path
|
|
@@ -1171,7 +1181,7 @@ class CLIInterface:
|
|
|
1171
1181
|
# Create table for server details
|
|
1172
1182
|
table = Table(
|
|
1173
1183
|
show_header=True,
|
|
1174
|
-
header_style=
|
|
1184
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1175
1185
|
box=box.ROUNDED,
|
|
1176
1186
|
border_style="green"
|
|
1177
1187
|
)
|
|
@@ -1345,7 +1355,7 @@ class CLIInterface:
|
|
|
1345
1355
|
# Budget section
|
|
1346
1356
|
if budget_limit > 0:
|
|
1347
1357
|
content_parts.append("")
|
|
1348
|
-
content_parts.append(
|
|
1358
|
+
content_parts.append("[bold cyan]Budget Status:[/bold cyan]")
|
|
1349
1359
|
content_parts.append(f" • Budget Limit: [yellow]${budget_limit:.2f} USD[/yellow]")
|
|
1350
1360
|
|
|
1351
1361
|
if budget_exceeded:
|
|
@@ -1473,7 +1483,7 @@ class CLIInterface:
|
|
|
1473
1483
|
f"[dim]({input_str})[/dim]"
|
|
1474
1484
|
)
|
|
1475
1485
|
|
|
1476
|
-
def display_tool_result(self, tool_name: str, result: str, is_error: bool = False):
|
|
1486
|
+
def display_tool_result(self, tool_name: str, result: str, is_error: bool = False): # noqa: S1172
|
|
1477
1487
|
"""
|
|
1478
1488
|
Display a tool result during chat.
|
|
1479
1489
|
|
|
@@ -1555,7 +1565,7 @@ class CLIInterface:
|
|
|
1555
1565
|
found_files = FileManager.scan_directory(str(path.absolute()), recursive=recursive)
|
|
1556
1566
|
|
|
1557
1567
|
if not found_files:
|
|
1558
|
-
self.print_warning(
|
|
1568
|
+
self.print_warning(" No supported files found in directory")
|
|
1559
1569
|
continue
|
|
1560
1570
|
|
|
1561
1571
|
self.print_success(f" Found {len(found_files)} supported file(s)")
|
|
@@ -1605,7 +1615,6 @@ class CLIInterface:
|
|
|
1605
1615
|
|
|
1606
1616
|
else:
|
|
1607
1617
|
self.print_error(f"Invalid path type: {input_path}")
|
|
1608
|
-
continue
|
|
1609
1618
|
|
|
1610
1619
|
if file_attachments:
|
|
1611
1620
|
self.console.print()
|
|
@@ -1636,7 +1645,7 @@ class CLIInterface:
|
|
|
1636
1645
|
# Create table for attached files
|
|
1637
1646
|
table = Table(
|
|
1638
1647
|
show_header=True,
|
|
1639
|
-
header_style=
|
|
1648
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1640
1649
|
box=box.ROUNDED,
|
|
1641
1650
|
border_style="blue"
|
|
1642
1651
|
)
|
|
@@ -1700,7 +1709,7 @@ class CLIInterface:
|
|
|
1700
1709
|
# Create table for transactions
|
|
1701
1710
|
table = Table(
|
|
1702
1711
|
show_header=True,
|
|
1703
|
-
header_style=
|
|
1712
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1704
1713
|
box=box.ROUNDED,
|
|
1705
1714
|
border_style="yellow"
|
|
1706
1715
|
)
|
|
@@ -1746,7 +1755,7 @@ class CLIInterface:
|
|
|
1746
1755
|
|
|
1747
1756
|
# Create details table
|
|
1748
1757
|
details_table = Table(show_header=False, box=None, padding=(0, 2))
|
|
1749
|
-
details_table.add_column("Label", style=
|
|
1758
|
+
details_table.add_column("Label", style=_STYLE_BOLD_YELLOW)
|
|
1750
1759
|
details_table.add_column("Value", style="white")
|
|
1751
1760
|
|
|
1752
1761
|
timestamp = datetime.fromisoformat(transaction['transaction_timestamp'])
|
|
@@ -1781,7 +1790,7 @@ class CLIInterface:
|
|
|
1781
1790
|
self.console.print()
|
|
1782
1791
|
try:
|
|
1783
1792
|
input_formatted = json.dumps(json.loads(transaction['tool_input']), indent=2)
|
|
1784
|
-
except:
|
|
1793
|
+
except ValueError:
|
|
1785
1794
|
input_formatted = transaction['tool_input']
|
|
1786
1795
|
|
|
1787
1796
|
self.console.print(Panel(
|
|
@@ -1812,7 +1821,7 @@ class CLIInterface:
|
|
|
1812
1821
|
"""
|
|
1813
1822
|
# Create stats table
|
|
1814
1823
|
stats_table = Table(show_header=False, box=None, padding=(0, 2))
|
|
1815
|
-
stats_table.add_column("Metric", style=
|
|
1824
|
+
stats_table.add_column("Metric", style=_STYLE_BOLD_YELLOW)
|
|
1816
1825
|
stats_table.add_column("Value", style="white")
|
|
1817
1826
|
|
|
1818
1827
|
stats_table.add_row("Total Transactions", f"{stats['total_transactions']:,}")
|
|
@@ -1831,7 +1840,7 @@ class CLIInterface:
|
|
|
1831
1840
|
self.console.print()
|
|
1832
1841
|
tools_table = Table(
|
|
1833
1842
|
show_header=True,
|
|
1834
|
-
header_style=
|
|
1843
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1835
1844
|
box=box.ROUNDED,
|
|
1836
1845
|
border_style="green"
|
|
1837
1846
|
)
|
|
@@ -1852,7 +1861,7 @@ class CLIInterface:
|
|
|
1852
1861
|
self.console.print()
|
|
1853
1862
|
conv_table = Table(
|
|
1854
1863
|
show_header=True,
|
|
1855
|
-
header_style=
|
|
1864
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1856
1865
|
box=box.ROUNDED,
|
|
1857
1866
|
border_style="cyan"
|
|
1858
1867
|
)
|
|
@@ -1885,7 +1894,7 @@ class CLIInterface:
|
|
|
1885
1894
|
|
|
1886
1895
|
table = Table(
|
|
1887
1896
|
show_header=True,
|
|
1888
|
-
header_style=
|
|
1897
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
1889
1898
|
box=box.ROUNDED,
|
|
1890
1899
|
border_style="cyan"
|
|
1891
1900
|
)
|
|
@@ -2046,9 +2055,9 @@ class CLIInterface:
|
|
|
2046
2055
|
for i, state in enumerate(server_states, 1):
|
|
2047
2056
|
status = "[green]enabled[/green]" if state['enabled'] else "[red]disabled[/red]"
|
|
2048
2057
|
self.console.print(f" [{i}] {state['server_name']} ({status})")
|
|
2049
|
-
self.console.print(
|
|
2058
|
+
self.console.print(_MSG_CANCEL_OPTION)
|
|
2050
2059
|
|
|
2051
|
-
choice = self.get_input(
|
|
2060
|
+
choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2052
2061
|
try:
|
|
2053
2062
|
idx = int(choice)
|
|
2054
2063
|
if idx == 0:
|
|
@@ -2056,10 +2065,10 @@ class CLIInterface:
|
|
|
2056
2065
|
if 1 <= idx <= len(server_states):
|
|
2057
2066
|
return server_states[idx - 1]['server_name']
|
|
2058
2067
|
else:
|
|
2059
|
-
self.print_error(
|
|
2068
|
+
self.print_error(_MSG_INVALID_CHOICE)
|
|
2060
2069
|
return None
|
|
2061
2070
|
except ValueError:
|
|
2062
|
-
self.print_error(
|
|
2071
|
+
self.print_error(_MSG_INVALID_INPUT)
|
|
2063
2072
|
return None
|
|
2064
2073
|
|
|
2065
2074
|
# =========================================================================
|
|
@@ -2103,7 +2112,7 @@ class CLIInterface:
|
|
|
2103
2112
|
menu_panel = Panel(
|
|
2104
2113
|
menu_content,
|
|
2105
2114
|
title="[bold bright_magenta]AUTONOMOUS ACTIONS[/bold bright_magenta]",
|
|
2106
|
-
border_style=
|
|
2115
|
+
border_style=_STYLE_BOLD_CYAN,
|
|
2107
2116
|
box=box.HEAVY,
|
|
2108
2117
|
padding=(0, 1)
|
|
2109
2118
|
)
|
|
@@ -2149,7 +2158,7 @@ class CLIInterface:
|
|
|
2149
2158
|
|
|
2150
2159
|
table = Table(
|
|
2151
2160
|
show_header=True,
|
|
2152
|
-
header_style=
|
|
2161
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
2153
2162
|
box=box.ROUNDED,
|
|
2154
2163
|
border_style="cyan"
|
|
2155
2164
|
)
|
|
@@ -2229,7 +2238,7 @@ class CLIInterface:
|
|
|
2229
2238
|
|
|
2230
2239
|
table = Table(
|
|
2231
2240
|
show_header=True,
|
|
2232
|
-
header_style=
|
|
2241
|
+
header_style=_STYLE_BOLD_MAGENTA,
|
|
2233
2242
|
box=box.ROUNDED,
|
|
2234
2243
|
border_style="cyan"
|
|
2235
2244
|
)
|
|
@@ -2264,7 +2273,7 @@ class CLIInterface:
|
|
|
2264
2273
|
completed = datetime.fromisoformat(completed.replace('Z', '+00:00'))
|
|
2265
2274
|
duration = (completed - started).total_seconds()
|
|
2266
2275
|
duration_str = f"{duration:.1f}s"
|
|
2267
|
-
except:
|
|
2276
|
+
except (ValueError, TypeError):
|
|
2268
2277
|
duration_str = "N/A"
|
|
2269
2278
|
else:
|
|
2270
2279
|
duration_str = "N/A"
|
|
@@ -2347,9 +2356,9 @@ class CLIInterface:
|
|
|
2347
2356
|
for i, action in enumerate(actions, 1):
|
|
2348
2357
|
status = "[green]enabled[/green]" if action['is_enabled'] else "[red]disabled[/red]"
|
|
2349
2358
|
self.console.print(f" [{i}] {action['name']} ({status})")
|
|
2350
|
-
self.console.print(
|
|
2359
|
+
self.console.print(_MSG_CANCEL_OPTION)
|
|
2351
2360
|
|
|
2352
|
-
choice = self.get_input(
|
|
2361
|
+
choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2353
2362
|
try:
|
|
2354
2363
|
idx = int(choice)
|
|
2355
2364
|
if idx == 0:
|
|
@@ -2357,10 +2366,10 @@ class CLIInterface:
|
|
|
2357
2366
|
if 1 <= idx <= len(actions):
|
|
2358
2367
|
return actions[idx - 1]['id']
|
|
2359
2368
|
else:
|
|
2360
|
-
self.print_error(
|
|
2369
|
+
self.print_error(_MSG_INVALID_CHOICE)
|
|
2361
2370
|
return None
|
|
2362
2371
|
except ValueError:
|
|
2363
|
-
self.print_error(
|
|
2372
|
+
self.print_error(_MSG_INVALID_INPUT)
|
|
2364
2373
|
return None
|
|
2365
2374
|
|
|
2366
2375
|
def select_run(self, runs: List[Dict], prompt: str = "Select a run") -> Optional[int]:
|
|
@@ -2383,9 +2392,9 @@ class CLIInterface:
|
|
|
2383
2392
|
status = run.get('status', 'unknown')
|
|
2384
2393
|
started = str(run.get('started_at', ''))[:16]
|
|
2385
2394
|
self.console.print(f" [{i}] Run {run['id']} - {status} ({started})")
|
|
2386
|
-
self.console.print(
|
|
2395
|
+
self.console.print(_MSG_CANCEL_OPTION)
|
|
2387
2396
|
|
|
2388
|
-
choice = self.get_input(
|
|
2397
|
+
choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2389
2398
|
try:
|
|
2390
2399
|
idx = int(choice)
|
|
2391
2400
|
if idx == 0:
|
|
@@ -2393,10 +2402,10 @@ class CLIInterface:
|
|
|
2393
2402
|
if 1 <= idx <= len(runs):
|
|
2394
2403
|
return runs[idx - 1]['id']
|
|
2395
2404
|
else:
|
|
2396
|
-
self.print_error(
|
|
2405
|
+
self.print_error(_MSG_INVALID_CHOICE)
|
|
2397
2406
|
return None
|
|
2398
2407
|
except ValueError:
|
|
2399
|
-
self.print_error(
|
|
2408
|
+
self.print_error(_MSG_INVALID_INPUT)
|
|
2400
2409
|
return None
|
|
2401
2410
|
|
|
2402
2411
|
def select_export_format(self) -> Optional[str]:
|
|
@@ -2410,9 +2419,9 @@ class CLIInterface:
|
|
|
2410
2419
|
self.console.print(" [1] Plain Text")
|
|
2411
2420
|
self.console.print(" [2] HTML")
|
|
2412
2421
|
self.console.print(" [3] Markdown")
|
|
2413
|
-
self.console.print(
|
|
2422
|
+
self.console.print(_MSG_CANCEL_OPTION)
|
|
2414
2423
|
|
|
2415
|
-
choice = self.get_input(
|
|
2424
|
+
choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2416
2425
|
format_map = {'1': 'text', '2': 'html', '3': 'markdown'}
|
|
2417
2426
|
return format_map.get(choice)
|
|
2418
2427
|
|
|
@@ -2459,7 +2468,7 @@ class CLIInterface:
|
|
|
2459
2468
|
friendly_name = extract_friendly_model_name(model.get('id', ''))
|
|
2460
2469
|
self.console.print(f" [{i}] {friendly_name}")
|
|
2461
2470
|
|
|
2462
|
-
model_choice = self.get_input(
|
|
2471
|
+
model_choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2463
2472
|
try:
|
|
2464
2473
|
model_idx = int(model_choice) - 1
|
|
2465
2474
|
if model_idx < 0 or model_idx >= len(available_models):
|
|
@@ -2467,7 +2476,7 @@ class CLIInterface:
|
|
|
2467
2476
|
return None
|
|
2468
2477
|
model_id = available_models[model_idx]['id']
|
|
2469
2478
|
except ValueError:
|
|
2470
|
-
self.print_error(
|
|
2479
|
+
self.print_error(_MSG_INVALID_INPUT)
|
|
2471
2480
|
return None
|
|
2472
2481
|
|
|
2473
2482
|
# Step 5: Schedule type
|
|
@@ -2475,7 +2484,7 @@ class CLIInterface:
|
|
|
2475
2484
|
self.console.print(" [1] One-off (run once at specific time)")
|
|
2476
2485
|
self.console.print(" [2] Recurring (run on schedule)")
|
|
2477
2486
|
|
|
2478
|
-
schedule_choice = self.get_input(
|
|
2487
|
+
schedule_choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2479
2488
|
if schedule_choice == '1':
|
|
2480
2489
|
schedule_type = 'one_off'
|
|
2481
2490
|
self.console.print("\n[dim]Enter date/time in format: YYYY-MM-DD HH:MM[/dim]")
|
|
@@ -2504,7 +2513,7 @@ class CLIInterface:
|
|
|
2504
2513
|
self.console.print(" [1] Fresh - Start with clean context each run")
|
|
2505
2514
|
self.console.print(" [2] Cumulative - Carry context from previous runs")
|
|
2506
2515
|
|
|
2507
|
-
context_choice = self.get_input(
|
|
2516
|
+
context_choice = self.get_input(_MSG_ENTER_CHOICE)
|
|
2508
2517
|
context_mode = 'cumulative' if context_choice == '2' else 'fresh'
|
|
2509
2518
|
|
|
2510
2519
|
# Step 7: Max failures
|