sentinel-ai-os 1.0__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.
Files changed (48) hide show
  1. sentinel/__init__.py +0 -0
  2. sentinel/auth.py +40 -0
  3. sentinel/cli.py +9 -0
  4. sentinel/core/__init__.py +0 -0
  5. sentinel/core/agent.py +298 -0
  6. sentinel/core/audit.py +48 -0
  7. sentinel/core/cognitive.py +94 -0
  8. sentinel/core/config.py +99 -0
  9. sentinel/core/llm.py +143 -0
  10. sentinel/core/registry.py +351 -0
  11. sentinel/core/scheduler.py +61 -0
  12. sentinel/core/schema.py +11 -0
  13. sentinel/core/setup.py +101 -0
  14. sentinel/core/ui.py +112 -0
  15. sentinel/main.py +110 -0
  16. sentinel/paths.py +77 -0
  17. sentinel/tools/__init__.py +0 -0
  18. sentinel/tools/apps.py +462 -0
  19. sentinel/tools/audio.py +30 -0
  20. sentinel/tools/browser.py +66 -0
  21. sentinel/tools/calendar_ops.py +163 -0
  22. sentinel/tools/clock.py +25 -0
  23. sentinel/tools/context.py +40 -0
  24. sentinel/tools/desktop.py +116 -0
  25. sentinel/tools/email_ops.py +62 -0
  26. sentinel/tools/factory.py +125 -0
  27. sentinel/tools/file_ops.py +81 -0
  28. sentinel/tools/flights.py +62 -0
  29. sentinel/tools/gmail_auth.py +47 -0
  30. sentinel/tools/indexer.py +156 -0
  31. sentinel/tools/installer.py +69 -0
  32. sentinel/tools/macros.py +58 -0
  33. sentinel/tools/memory_ops.py +281 -0
  34. sentinel/tools/navigation.py +109 -0
  35. sentinel/tools/notes.py +78 -0
  36. sentinel/tools/office.py +67 -0
  37. sentinel/tools/organizer.py +150 -0
  38. sentinel/tools/smart_index.py +76 -0
  39. sentinel/tools/sql_index.py +186 -0
  40. sentinel/tools/system_ops.py +86 -0
  41. sentinel/tools/vision.py +94 -0
  42. sentinel/tools/weather_ops.py +59 -0
  43. sentinel_ai_os-1.0.dist-info/METADATA +282 -0
  44. sentinel_ai_os-1.0.dist-info/RECORD +48 -0
  45. sentinel_ai_os-1.0.dist-info/WHEEL +5 -0
  46. sentinel_ai_os-1.0.dist-info/entry_points.txt +2 -0
  47. sentinel_ai_os-1.0.dist-info/licenses/LICENSE +21 -0
  48. sentinel_ai_os-1.0.dist-info/top_level.txt +1 -0
sentinel/core/ui.py ADDED
@@ -0,0 +1,112 @@
1
+ # FILE: core/ui.py
2
+ from rich.console import Console
3
+ from rich.panel import Panel
4
+ from rich.markdown import Markdown
5
+ from rich import box
6
+ from rich.table import Table
7
+
8
+
9
+ class UI:
10
+ console = Console()
11
+
12
+ @staticmethod
13
+ def print_banner():
14
+ logo = """
15
+ ███████╗███████╗███╗ ██╗████████╗██╗███╗ ██╗███████╗██╗
16
+ ██╔════╝██╔════╝████╗ ██║╚══██╔══╝██║████╗ ██║██╔════╝██║
17
+ ███████╗█████╗ ██╔██╗ ██║ ██║ ██║██╔██╗ ██║█████╗ ██║
18
+ ╚════██║██╔══╝ ██║╚██╗██║ ██║ ██║██║╚██╗██║██╔══╝ ██║
19
+ ███████║███████╗██║ ╚████║ ██║ ██║██║ ╚████║███████╗███████╗
20
+ ╚══════╝╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝
21
+ """
22
+ UI.console.print(f"[bold cyan]{logo}[/bold cyan]")
23
+ UI.console.print("[dim]OPERATING SYSTEM v1.0[/dim]\n")
24
+
25
+ @staticmethod
26
+ def print_system(msg):
27
+ UI.console.print(f"[dim]System: {msg}[/dim]")
28
+
29
+ @staticmethod
30
+ def print_success(msg):
31
+ UI.console.print(f"[bold green]✔ {msg}[/bold green]")
32
+
33
+ @staticmethod
34
+ def print_warning(msg):
35
+ UI.console.print(f"[bold yellow]⚠ {msg}[/bold yellow]")
36
+
37
+ @staticmethod
38
+ def print_error(msg):
39
+ UI.console.print(Panel(
40
+ f"[bold white]{msg}[/bold white]",
41
+ title="System Alert",
42
+ border_style="red",
43
+ box=box.ROUNDED,
44
+ expand=False
45
+ ))
46
+
47
+ @staticmethod
48
+ def print_agent(text, model=None):
49
+ """The SENTINEL Response Panel."""
50
+ if not isinstance(text, Markdown):
51
+ text = Markdown(str(text))
52
+
53
+ # Add Model Info to Title
54
+ title = "[bold cyan]SENTINEL[/bold cyan]"
55
+ if model:
56
+ title += f" [dim]({model})[/dim]"
57
+
58
+ UI.console.print(Panel(
59
+ text,
60
+ title=title,
61
+ title_align="left",
62
+ border_style="cyan",
63
+ box=box.ROUNDED,
64
+ padding=(1, 2),
65
+ expand=True
66
+ ))
67
+
68
+ @staticmethod
69
+ def print_tool(tool_name):
70
+ UI.console.print(f"[dim] ⚙ Executing: {tool_name}...[/dim]")
71
+
72
+ @staticmethod
73
+ def print_result(result):
74
+ text = str(result)
75
+ if len(text) > 400:
76
+ text = text[:400] + "... (truncated)"
77
+ UI.console.print(Panel(
78
+ text,
79
+ title="Action Result",
80
+ border_style="dim white",
81
+ box=box.ROUNDED,
82
+ expand=False
83
+ ))
84
+
85
+ @staticmethod
86
+ def print_help():
87
+ table = Table(title="Sentinel Control Panel", border_style="cyan", box=box.ROUNDED)
88
+ table.add_column("Command", style="bold cyan")
89
+ table.add_column("Description", style="white")
90
+
91
+ table.add_row("/help", "Show this menu")
92
+ table.add_row("/exit", "Shutdown system")
93
+ table.add_row("/status", "View current model, provider, and memory stats")
94
+ table.add_row("/memory [n]", "Set Context Window size (e.g., /memory 5)")
95
+ table.add_row("/log [on/off]", "Toggle audit logging (Default: OFF)")
96
+
97
+ table.add_row("/clear", "Clear active chat memory (RAM only)")
98
+ table.add_row("/wipe", "Wipe long-term memory (Vector DB + brain.db)")
99
+ table.add_row("/factory_reset", "[bold red]FULL FACTORY RESET[/bold red] (Deletes EVERYTHING)")
100
+
101
+ table.add_row("/switch [p] [m]", "Switch Brain (e.g., /switch groq llama3)")
102
+ table.add_row("/setkey [p] [k]", "Update API Key")
103
+
104
+ UI.console.print(table)
105
+
106
+ @staticmethod
107
+ def get_input():
108
+ try:
109
+ UI.console.print()
110
+ return UI.console.input("[bold cyan]>>> [/bold cyan]")
111
+ except KeyboardInterrupt:
112
+ return None
sentinel/main.py ADDED
@@ -0,0 +1,110 @@
1
+ # FILE: main.py
2
+ import typer
3
+ from sentinel.core.config import ConfigManager
4
+ from sentinel.core.agent import SentinelAgent
5
+ from sentinel.core.ui import UI
6
+ from sentinel.core.registry import initialize_tools
7
+ from sentinel.core.setup import setup_wizard
8
+
9
+ app = typer.Typer(
10
+ name="Sentinel",
11
+ help="Autonomous AI Agent for your OS",
12
+ add_completion=False,
13
+ no_args_is_help=False
14
+ )
15
+
16
+
17
+ def boot_sequence(briefing: bool = False):
18
+ """
19
+ Shared startup logic for both default run and 'start' command.
20
+ """
21
+ UI.console.clear()
22
+
23
+ # 1. Check Configuration
24
+ cfg = ConfigManager()
25
+ if not cfg.exists():
26
+ setup_wizard()
27
+ cfg = ConfigManager() # Reload after wizard
28
+
29
+ # 2. Boot Up
30
+ UI.print_banner()
31
+
32
+ # Check for keys
33
+ # We check if ANY key is present or if using Ollama
34
+ has_key = (
35
+ cfg.get_key("openai") or
36
+ cfg.get_key("anthropic") or
37
+ cfg.get_key("groq") or
38
+ cfg.get("llm.provider") == "ollama"
39
+ )
40
+
41
+ if not has_key:
42
+ UI.print_warning("No LLM API Key found. System running in Limited Mode.")
43
+ else:
44
+ provider = cfg.get("llm.provider", "unknown")
45
+ UI.print_system(f"Brain Active: [green]{provider.upper()}[/green]")
46
+
47
+ # 3. Initialize Background Services
48
+ initialize_tools()
49
+
50
+ # 4. Run Briefing (If requested)
51
+ if briefing:
52
+ if has_key:
53
+ UI.print_system("Generating Daily Briefing...")
54
+ try:
55
+ from sentinel.core.cognitive import get_daily_briefing
56
+ report = get_daily_briefing(cfg)
57
+ UI.print_agent(report)
58
+ except Exception as e:
59
+ UI.print_error(f"Briefing failed: {e}")
60
+ else:
61
+ UI.print_error("Skipping Daily Briefing (Offline Mode).")
62
+
63
+ # 5. Start Agent Loop
64
+ try:
65
+ agent = SentinelAgent(cfg)
66
+ agent.run_loop()
67
+ except KeyboardInterrupt:
68
+ UI.print_system("Shutting down...")
69
+ except Exception as e:
70
+ UI.print_error(f"Critical System Failure: {e}")
71
+
72
+
73
+ @app.callback(invoke_without_command=True)
74
+ def main(
75
+ ctx: typer.Context,
76
+ briefing: bool = typer.Option(False, "--briefing", "-b", help="Run Daily Briefing on startup")
77
+ ):
78
+ """
79
+ Main Entry Point. Checks state and routes to Setup or Runtime.
80
+ """
81
+ # If a subcommand (like 'config' or 'auth') is called, skip this default boot
82
+ if ctx.invoked_subcommand is not None:
83
+ return
84
+
85
+ boot_sequence(briefing=briefing)
86
+
87
+
88
+ @app.command()
89
+ def start(
90
+ briefing: bool = typer.Option(False, "--briefing", "-b", help="Run Daily Briefing on startup")
91
+ ):
92
+ """Explicit start command."""
93
+ boot_sequence(briefing=briefing)
94
+
95
+
96
+ @app.command()
97
+ def config():
98
+ """Re-run the configuration wizard."""
99
+ setup_wizard()
100
+
101
+
102
+ @app.command()
103
+ def auth():
104
+ """Run the Google Authentication fix tool."""
105
+ from sentinel.auth import fix_authentication
106
+ fix_authentication()
107
+
108
+
109
+ if __name__ == "__main__":
110
+ app()
sentinel/paths.py ADDED
@@ -0,0 +1,77 @@
1
+ # FILE: sentinel/core/paths.py
2
+ import os
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ # ==========================================
7
+ # 1. USER DATA STORAGE (Mutable)
8
+ # Stores DBs, Configs, Logs, and Auth Tokens
9
+ # Location: ~/.sentinel (Cross-platform)
10
+ # ==========================================
11
+
12
+ USER_DATA_DIR = Path.home() / ".sentinel"
13
+ USER_DATA_DIR.mkdir(parents=True, exist_ok=True)
14
+
15
+ # Subdirectories
16
+ LOGS_DIR = USER_DATA_DIR / "logs"
17
+ LOGS_DIR.mkdir(exist_ok=True)
18
+
19
+ DRAFTS_DIR = USER_DATA_DIR / "drafts"
20
+ DRAFTS_DIR.mkdir(exist_ok=True)
21
+
22
+ # Critical System Files
23
+ CONFIG_PATH = USER_DATA_DIR / "config.json"
24
+ DB_PATH = USER_DATA_DIR / "brain.db"
25
+ VECTOR_PATH = USER_DATA_DIR / "brain_vectors" # ChromaDB folder
26
+ AUDIT_LOG_PATH = USER_DATA_DIR / "audit_log.jsonl"
27
+ MEMORY_FILE = USER_DATA_DIR / "memory.json"
28
+
29
+ # Search Indexes
30
+ FILE_INDEX_DB = USER_DATA_DIR / "file_index.db"
31
+ SMART_INDEX_DB = USER_DATA_DIR / "smart_files.db"
32
+
33
+ # Authentication
34
+ CREDENTIALS_PATH = USER_DATA_DIR / "credentials.json"
35
+ TOKEN_PATH = USER_DATA_DIR / "token.json"
36
+
37
+
38
+ # ==========================================
39
+ # 2. PACKAGE ASSETS (Immutable)
40
+ # Locates scripts/tools bundled inside the pip package
41
+ # Location: .../site-packages/sentinel/scripts/
42
+ # ==========================================
43
+
44
+ def get_script_path(filename: str) -> str:
45
+ """
46
+ Returns the absolute path to a script bundled inside the pip package.
47
+ Expects scripts to be in: src/sentinel/scripts/
48
+ """
49
+ # This file is in: .../sentinel/core/paths.py
50
+ # We want: .../sentinel/scripts/filename
51
+
52
+ # Get the directory of THIS file (core/)
53
+ current_dir = os.path.dirname(os.path.abspath(__file__))
54
+
55
+ # Go up one level to the package root (sentinel/)
56
+ pkg_root = os.path.dirname(current_dir)
57
+
58
+ # Target path
59
+ script_path = os.path.join(pkg_root, "scripts", filename)
60
+
61
+ if not os.path.exists(script_path):
62
+ # Fallback for Development Mode (running from source without pip install)
63
+ # In dev repo: sentinel/core/paths.py -> ../../../scripts/
64
+ repo_root = os.path.dirname(os.path.dirname(pkg_root))
65
+ dev_path = os.path.join(repo_root, "scripts", filename)
66
+
67
+ if os.path.exists(dev_path):
68
+ return dev_path
69
+
70
+ # If we still can't find it, that's a build error
71
+ raise FileNotFoundError(
72
+ f"Could not find bundled script '{filename}'.\n"
73
+ f"Checked: {script_path}\n"
74
+ f"Checked: {dev_path}"
75
+ )
76
+
77
+ return script_path
File without changes