lulabell-engine 0.3.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.
Files changed (140) hide show
  1. lulabell_engine-0.3.0/LICENSE +21 -0
  2. lulabell_engine-0.3.0/MANIFEST.in +6 -0
  3. lulabell_engine-0.3.0/PKG-INFO +121 -0
  4. lulabell_engine-0.3.0/README.md +85 -0
  5. lulabell_engine-0.3.0/config.template.yaml +51 -0
  6. lulabell_engine-0.3.0/lulabell_engine/__init__.py +2 -0
  7. lulabell_engine-0.3.0/lulabell_engine/actioncore/__init__.py +2 -0
  8. lulabell_engine-0.3.0/lulabell_engine/actioncore/api.py +269 -0
  9. lulabell_engine-0.3.0/lulabell_engine/actioncore/cli.py +376 -0
  10. lulabell_engine-0.3.0/lulabell_engine/actioncore/config.py +42 -0
  11. lulabell_engine-0.3.0/lulabell_engine/actioncore/core.py +166 -0
  12. lulabell_engine-0.3.0/lulabell_engine/actioncore/executor.py +307 -0
  13. lulabell_engine-0.3.0/lulabell_engine/actioncore/listeners/__init__.py +0 -0
  14. lulabell_engine-0.3.0/lulabell_engine/actioncore/listeners/email_listener.py +132 -0
  15. lulabell_engine-0.3.0/lulabell_engine/actioncore/planner.py +315 -0
  16. lulabell_engine-0.3.0/lulabell_engine/actioncore/safety.py +180 -0
  17. lulabell_engine-0.3.0/lulabell_engine/actioncore/tasks/__init__.py +17 -0
  18. lulabell_engine-0.3.0/lulabell_engine/actioncore/tasks/email_task.py +61 -0
  19. lulabell_engine-0.3.0/lulabell_engine/actioncore/tasks/file_task.py +60 -0
  20. lulabell_engine-0.3.0/lulabell_engine/actioncore/tasks/llm_task.py +117 -0
  21. lulabell_engine-0.3.0/lulabell_engine/actioncore/tasks/plan_task.py +215 -0
  22. lulabell_engine-0.3.0/lulabell_engine/actioncore/tasks/system_task.py +113 -0
  23. lulabell_engine-0.3.0/lulabell_engine/actioncore/tools/__init__.py +42 -0
  24. lulabell_engine-0.3.0/lulabell_engine/actioncore/tools/bash.py +200 -0
  25. lulabell_engine-0.3.0/lulabell_engine/actioncore/tools/config.py +166 -0
  26. lulabell_engine-0.3.0/lulabell_engine/actioncore/tools/diagnose.py +268 -0
  27. lulabell_engine-0.3.0/lulabell_engine/actioncore/tools/docker.py +145 -0
  28. lulabell_engine-0.3.0/lulabell_engine/actioncore/tools/files.py +193 -0
  29. lulabell_engine-0.3.0/lulabell_engine/actioncore/tools/git.py +167 -0
  30. lulabell_engine-0.3.0/lulabell_engine/actioncore/tools/logs.py +139 -0
  31. lulabell_engine-0.3.0/lulabell_engine/actioncore/tools/systemd.py +146 -0
  32. lulabell_engine-0.3.0/lulabell_engine/actioncore/uap_handler.py +243 -0
  33. lulabell_engine-0.3.0/lulabell_engine/actioncore/validator.py +173 -0
  34. lulabell_engine-0.3.0/lulabell_engine/agent_manager.py +216 -0
  35. lulabell_engine-0.3.0/lulabell_engine/alerts.py +235 -0
  36. lulabell_engine-0.3.0/lulabell_engine/anchor/__init__.py +0 -0
  37. lulabell_engine-0.3.0/lulabell_engine/anchor/actions.py +0 -0
  38. lulabell_engine-0.3.0/lulabell_engine/anchor/bar.py +1213 -0
  39. lulabell_engine-0.3.0/lulabell_engine/anchor/chat.py +279 -0
  40. lulabell_engine-0.3.0/lulabell_engine/anchor/cli.py +320 -0
  41. lulabell_engine-0.3.0/lulabell_engine/anchor/config.py +67 -0
  42. lulabell_engine-0.3.0/lulabell_engine/anchor/core.py +242 -0
  43. lulabell_engine-0.3.0/lulabell_engine/anchor/crypto.py +115 -0
  44. lulabell_engine-0.3.0/lulabell_engine/anchor/homelab.py +0 -0
  45. lulabell_engine-0.3.0/lulabell_engine/anchor/identity.py +0 -0
  46. lulabell_engine-0.3.0/lulabell_engine/anchor/incubation.py +187 -0
  47. lulabell_engine-0.3.0/lulabell_engine/anchor/memory.py +151 -0
  48. lulabell_engine-0.3.0/lulabell_engine/anchor/notifications.py +155 -0
  49. lulabell_engine-0.3.0/lulabell_engine/anchor/personality.py +154 -0
  50. lulabell_engine-0.3.0/lulabell_engine/anchor/relevance.py +124 -0
  51. lulabell_engine-0.3.0/lulabell_engine/anchor/router.py +127 -0
  52. lulabell_engine-0.3.0/lulabell_engine/anchor/sanitizer.py +88 -0
  53. lulabell_engine-0.3.0/lulabell_engine/anchor/surrogates.py +0 -0
  54. lulabell_engine-0.3.0/lulabell_engine/anchor/tiers.py +100 -0
  55. lulabell_engine-0.3.0/lulabell_engine/api_keys.py +86 -0
  56. lulabell_engine-0.3.0/lulabell_engine/audit.py +404 -0
  57. lulabell_engine-0.3.0/lulabell_engine/auth.py +180 -0
  58. lulabell_engine-0.3.0/lulabell_engine/b2_routes.py +445 -0
  59. lulabell_engine-0.3.0/lulabell_engine/blackwell/__init__.py +3 -0
  60. lulabell_engine-0.3.0/lulabell_engine/blackwell/baseline.py +290 -0
  61. lulabell_engine-0.3.0/lulabell_engine/blackwell/drift.py +309 -0
  62. lulabell_engine-0.3.0/lulabell_engine/blackwell/embeddings.py +71 -0
  63. lulabell_engine-0.3.0/lulabell_engine/blackwell/routes.py +109 -0
  64. lulabell_engine-0.3.0/lulabell_engine/blackwell/summary.py +186 -0
  65. lulabell_engine-0.3.0/lulabell_engine/capabilities.py +248 -0
  66. lulabell_engine-0.3.0/lulabell_engine/cli.py +981 -0
  67. lulabell_engine-0.3.0/lulabell_engine/cli_summary.py +202 -0
  68. lulabell_engine-0.3.0/lulabell_engine/collectors/__init__.py +93 -0
  69. lulabell_engine-0.3.0/lulabell_engine/collectors/app_usage.py +68 -0
  70. lulabell_engine-0.3.0/lulabell_engine/collectors/audio_context.py +61 -0
  71. lulabell_engine-0.3.0/lulabell_engine/collectors/browser_history.py +103 -0
  72. lulabell_engine-0.3.0/lulabell_engine/collectors/clipboard.py +60 -0
  73. lulabell_engine-0.3.0/lulabell_engine/collectors/debug.py +117 -0
  74. lulabell_engine-0.3.0/lulabell_engine/collectors/keystrokes.py +80 -0
  75. lulabell_engine-0.3.0/lulabell_engine/collectors/launcher.py +223 -0
  76. lulabell_engine-0.3.0/lulabell_engine/collectors/network.py +78 -0
  77. lulabell_engine-0.3.0/lulabell_engine/collectors/presence.py +186 -0
  78. lulabell_engine-0.3.0/lulabell_engine/collectors/process_list.py +56 -0
  79. lulabell_engine-0.3.0/lulabell_engine/collectors/screen_context.py +68 -0
  80. lulabell_engine-0.3.0/lulabell_engine/collectors/system_stat.py +51 -0
  81. lulabell_engine-0.3.0/lulabell_engine/collectors/video.py +346 -0
  82. lulabell_engine-0.3.0/lulabell_engine/compression.py +495 -0
  83. lulabell_engine-0.3.0/lulabell_engine/config.py +533 -0
  84. lulabell_engine-0.3.0/lulabell_engine/config_loader.py +261 -0
  85. lulabell_engine-0.3.0/lulabell_engine/dashboard.py +556 -0
  86. lulabell_engine-0.3.0/lulabell_engine/database.py +790 -0
  87. lulabell_engine-0.3.0/lulabell_engine/distillation.py +416 -0
  88. lulabell_engine-0.3.0/lulabell_engine/extractor.py +1488 -0
  89. lulabell_engine-0.3.0/lulabell_engine/feedback.py +236 -0
  90. lulabell_engine-0.3.0/lulabell_engine/identity.py +1286 -0
  91. lulabell_engine-0.3.0/lulabell_engine/intelligence/__init__.py +2 -0
  92. lulabell_engine-0.3.0/lulabell_engine/intelligence/activity_score.py +403 -0
  93. lulabell_engine-0.3.0/lulabell_engine/intelligence/goal_drift.py +316 -0
  94. lulabell_engine-0.3.0/lulabell_engine/intelligence/routes.py +117 -0
  95. lulabell_engine-0.3.0/lulabell_engine/launcher.py +286 -0
  96. lulabell_engine-0.3.0/lulabell_engine/mcp_server.py +244 -0
  97. lulabell_engine-0.3.0/lulabell_engine/memory.py +341 -0
  98. lulabell_engine-0.3.0/lulabell_engine/monitors.py +187 -0
  99. lulabell_engine-0.3.0/lulabell_engine/observations.py +281 -0
  100. lulabell_engine-0.3.0/lulabell_engine/onboarding.py +276 -0
  101. lulabell_engine-0.3.0/lulabell_engine/patterns.py +1904 -0
  102. lulabell_engine-0.3.0/lulabell_engine/personality.py +303 -0
  103. lulabell_engine-0.3.0/lulabell_engine/pots.py +640 -0
  104. lulabell_engine-0.3.0/lulabell_engine/pots_linux.py +991 -0
  105. lulabell_engine-0.3.0/lulabell_engine/pots_manager.py +166 -0
  106. lulabell_engine-0.3.0/lulabell_engine/prune_conversations.py +133 -0
  107. lulabell_engine-0.3.0/lulabell_engine/relevance/__init__.py +10 -0
  108. lulabell_engine-0.3.0/lulabell_engine/relevance/baselines.py +356 -0
  109. lulabell_engine-0.3.0/lulabell_engine/relevance/correlator.py +348 -0
  110. lulabell_engine-0.3.0/lulabell_engine/relevance/routes.py +263 -0
  111. lulabell_engine-0.3.0/lulabell_engine/relevance/scorer.py +388 -0
  112. lulabell_engine-0.3.0/lulabell_engine/reminders.py +392 -0
  113. lulabell_engine-0.3.0/lulabell_engine/reminders_routes.py +126 -0
  114. lulabell_engine-0.3.0/lulabell_engine/scheduler.py +96 -0
  115. lulabell_engine-0.3.0/lulabell_engine/server.py +838 -0
  116. lulabell_engine-0.3.0/lulabell_engine/setup.py +337 -0
  117. lulabell_engine-0.3.0/lulabell_engine/static/app.js +611 -0
  118. lulabell_engine-0.3.0/lulabell_engine/static/index.html +131 -0
  119. lulabell_engine-0.3.0/lulabell_engine/static/style.css +824 -0
  120. lulabell_engine-0.3.0/lulabell_engine/subjects/__init__.py +1 -0
  121. lulabell_engine-0.3.0/lulabell_engine/subjects/camera.yaml +45 -0
  122. lulabell_engine-0.3.0/lulabell_engine/subjects/human.yaml +139 -0
  123. lulabell_engine-0.3.0/lulabell_engine/subjects/loader.py +85 -0
  124. lulabell_engine-0.3.0/lulabell_engine/subjects/vehicle.yaml +40 -0
  125. lulabell_engine-0.3.0/lulabell_engine/summary.py +221 -0
  126. lulabell_engine-0.3.0/lulabell_engine/uap/__init__.py +119 -0
  127. lulabell_engine-0.3.0/lulabell_engine/uap/backup.py +288 -0
  128. lulabell_engine-0.3.0/lulabell_engine/uap/config.py +37 -0
  129. lulabell_engine-0.3.0/lulabell_engine/uap/integrity.py +356 -0
  130. lulabell_engine-0.3.0/lulabell_engine/uap/routes.py +109 -0
  131. lulabell_engine-0.3.0/lulabell_engine/utils.py +189 -0
  132. lulabell_engine-0.3.0/lulabell_engine.egg-info/PKG-INFO +121 -0
  133. lulabell_engine-0.3.0/lulabell_engine.egg-info/SOURCES.txt +138 -0
  134. lulabell_engine-0.3.0/lulabell_engine.egg-info/dependency_links.txt +1 -0
  135. lulabell_engine-0.3.0/lulabell_engine.egg-info/entry_points.txt +2 -0
  136. lulabell_engine-0.3.0/lulabell_engine.egg-info/requires.txt +29 -0
  137. lulabell_engine-0.3.0/lulabell_engine.egg-info/top_level.txt +1 -0
  138. lulabell_engine-0.3.0/pyproject.toml +64 -0
  139. lulabell_engine-0.3.0/setup.cfg +4 -0
  140. lulabell_engine-0.3.0/tests/test_smoke.py +256 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jeff Draper
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ include README.md
2
+ include LICENSE
3
+ include config.template.yaml
4
+ recursive-include tethr_engine *.py
5
+ recursive-exclude * __pycache__
6
+ recursive-exclude * *.pyc
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.4
2
+ Name: lulabell-engine
3
+ Version: 0.3.0
4
+ Summary: Local-first behavioral intelligence engine with collectors, AI agent, and task executor
5
+ Author: Jeff Draper
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: fastapi>=0.100.0
11
+ Requires-Dist: uvicorn[standard]>=0.20.0
12
+ Requires-Dist: pydantic>=2.0.0
13
+ Requires-Dist: python-jose[cryptography]>=3.3.0
14
+ Requires-Dist: passlib[bcrypt]>=1.7.4
15
+ Requires-Dist: bcrypt>=4.0.0
16
+ Requires-Dist: pyyaml>=6.0
17
+ Requires-Dist: httpx>=0.24.0
18
+ Requires-Dist: requests>=2.28.0
19
+ Requires-Dist: psutil>=5.9.0
20
+ Requires-Dist: pillow>=9.0.0
21
+ Requires-Dist: sentence-transformers>=2.2.0
22
+ Requires-Dist: rich>=13.0.0
23
+ Requires-Dist: cryptography>=41.0.0
24
+ Requires-Dist: groq
25
+ Requires-Dist: anthropic
26
+ Requires-Dist: watchdog
27
+ Requires-Dist: mcp
28
+ Requires-Dist: pywin32>=305; sys_platform == "win32"
29
+ Provides-Extra: ml
30
+ Requires-Dist: scikit-learn; extra == "ml"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest; extra == "dev"
33
+ Requires-Dist: black; extra == "dev"
34
+ Requires-Dist: ruff; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ # tethr-engine
38
+
39
+ [![PyPI](https://img.shields.io/pypi/v/tethr-engine)](https://pypi.org/project/tethr-engine)
40
+ [![Python](https://img.shields.io/pypi/pyversions/tethr-engine)](https://pypi.org/project/tethr-engine)
41
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
42
+
43
+ TETHR is a local-first behavioral intelligence engine.
44
+ It passively observes your devices, detects behavioral
45
+ patterns without cloud processing, and serves real-time
46
+ presence context to AI agents in under 300 tokens.
47
+
48
+ ```bash
49
+ pip install tethr-engine
50
+ tethr start
51
+ ```
52
+
53
+ ---
54
+
55
+ ## What it does
56
+
57
+ - **Passive observation** — watches active windows, typing cadence, system state via background POTS process
58
+ - **Pattern detection** — identifies focus areas, app clusters, work rhythms from local data only
59
+ - **Agent-ready API** — `/identity/context` returns a compact behavioral summary, ready to inject into any system prompt
60
+ - **MCP server** — native Claude Desktop integration via `python -m tethr_engine.mcp_server`
61
+ - **Zero cloud** — everything stays on your device; Groq API used only for LLM inference calls
62
+
63
+ ---
64
+
65
+ ## Quick start
66
+
67
+ ```bash
68
+ pip install tethr-engine
69
+ tethr start # first run prompts for Groq API key, then serves on :8001
70
+ tethr status # confirm health
71
+ curl http://127.0.0.1:8001/identity/context
72
+ ```
73
+
74
+ Full walkthrough → [docs/quickstart.md](docs/quickstart.md)
75
+
76
+ ---
77
+
78
+ ## Agent integration
79
+
80
+ ```python
81
+ import requests
82
+
83
+ context = requests.get("http://127.0.0.1:8001/identity/context", timeout=3).json()["context"]
84
+ system_prompt = f"{your_base_prompt}\n\n[User context]\n{context}"
85
+ ```
86
+
87
+ Query once per session, inject into system prompt. ~200–300 tokens.
88
+
89
+ Full guide → [docs/integration.md](docs/integration.md)
90
+
91
+ ---
92
+
93
+ ## CLI
94
+
95
+ | Command | Description |
96
+ |---|---|
97
+ | `tethr start` | Start server on `localhost:8001` |
98
+ | `tethr start --host 0.0.0.0` | Network accessible |
99
+ | `tethr start --reload` | Dev mode |
100
+ | `tethr status` | Health check |
101
+ | `tethr version` | Print version |
102
+
103
+ ---
104
+
105
+ ## Configuring data storage
106
+
107
+ By default TETHR stores data in the package directory. To use an external drive set `data_path` in `config.yaml`:
108
+
109
+ ```yaml
110
+ data_path: D:\tethr-data
111
+ ```
112
+
113
+ Or set it during first-run setup when prompted. TETHR creates the directory if it does not exist.
114
+
115
+ ---
116
+
117
+ ## Links
118
+
119
+ - [PyPI](https://pypi.org/project/tethr-engine)
120
+ - [Quickstart](docs/quickstart.md)
121
+ - [Integration guide](docs/integration.md)
@@ -0,0 +1,85 @@
1
+ # tethr-engine
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/tethr-engine)](https://pypi.org/project/tethr-engine)
4
+ [![Python](https://img.shields.io/pypi/pyversions/tethr-engine)](https://pypi.org/project/tethr-engine)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
6
+
7
+ TETHR is a local-first behavioral intelligence engine.
8
+ It passively observes your devices, detects behavioral
9
+ patterns without cloud processing, and serves real-time
10
+ presence context to AI agents in under 300 tokens.
11
+
12
+ ```bash
13
+ pip install tethr-engine
14
+ tethr start
15
+ ```
16
+
17
+ ---
18
+
19
+ ## What it does
20
+
21
+ - **Passive observation** — watches active windows, typing cadence, system state via background POTS process
22
+ - **Pattern detection** — identifies focus areas, app clusters, work rhythms from local data only
23
+ - **Agent-ready API** — `/identity/context` returns a compact behavioral summary, ready to inject into any system prompt
24
+ - **MCP server** — native Claude Desktop integration via `python -m tethr_engine.mcp_server`
25
+ - **Zero cloud** — everything stays on your device; Groq API used only for LLM inference calls
26
+
27
+ ---
28
+
29
+ ## Quick start
30
+
31
+ ```bash
32
+ pip install tethr-engine
33
+ tethr start # first run prompts for Groq API key, then serves on :8001
34
+ tethr status # confirm health
35
+ curl http://127.0.0.1:8001/identity/context
36
+ ```
37
+
38
+ Full walkthrough → [docs/quickstart.md](docs/quickstart.md)
39
+
40
+ ---
41
+
42
+ ## Agent integration
43
+
44
+ ```python
45
+ import requests
46
+
47
+ context = requests.get("http://127.0.0.1:8001/identity/context", timeout=3).json()["context"]
48
+ system_prompt = f"{your_base_prompt}\n\n[User context]\n{context}"
49
+ ```
50
+
51
+ Query once per session, inject into system prompt. ~200–300 tokens.
52
+
53
+ Full guide → [docs/integration.md](docs/integration.md)
54
+
55
+ ---
56
+
57
+ ## CLI
58
+
59
+ | Command | Description |
60
+ |---|---|
61
+ | `tethr start` | Start server on `localhost:8001` |
62
+ | `tethr start --host 0.0.0.0` | Network accessible |
63
+ | `tethr start --reload` | Dev mode |
64
+ | `tethr status` | Health check |
65
+ | `tethr version` | Print version |
66
+
67
+ ---
68
+
69
+ ## Configuring data storage
70
+
71
+ By default TETHR stores data in the package directory. To use an external drive set `data_path` in `config.yaml`:
72
+
73
+ ```yaml
74
+ data_path: D:\tethr-data
75
+ ```
76
+
77
+ Or set it during first-run setup when prompted. TETHR creates the directory if it does not exist.
78
+
79
+ ---
80
+
81
+ ## Links
82
+
83
+ - [PyPI](https://pypi.org/project/tethr-engine)
84
+ - [Quickstart](docs/quickstart.md)
85
+ - [Integration guide](docs/integration.md)
@@ -0,0 +1,51 @@
1
+ # TETHR Engine Configuration Template
2
+ # Copy this to data/config.yaml and fill in your values.
3
+ # config.yaml is gitignored — never commit your actual secrets.
4
+
5
+ # === REQUIRED ===
6
+ data_path: "D:\\TETHR Data" # Where to store database + files
7
+ user_id: "" # Populated automatically during setup
8
+
9
+ # === AUTHENTICATION ===
10
+ username: "" # Your login username
11
+ port: 8001 # Server port
12
+
13
+ # === API KEYS (Optional - enables features) ===
14
+ groq_api_key: "" # For LLM - get from console.groq.com
15
+ tavily_api_key: "" # For web search - get from app.tavily.com
16
+ telegram_token: "" # For Telegram - get from @BotFather
17
+ telegram_chat_id: "" # Your Telegram chat ID (message @userinfobot)
18
+
19
+ # === AGENT CONFIG ===
20
+ agent_name: "" # Your agent's name (set during onboarding)
21
+ agent_hatched: false # Set to true after first conversation
22
+
23
+ # === DEVICE ===
24
+ device_id: "" # This device's hostname (auto-set)
25
+
26
+ # === OPTIONAL INTEGRATIONS ===
27
+ # zepp_token: "" # Amazfit/Zepp API
28
+ # spotify_token: "" # Spotify API
29
+
30
+ # === PROACTIVE ===
31
+ proactive:
32
+ enabled: true
33
+ schedule:
34
+ work_days: [mon, tue, wed, thu, fri]
35
+ work_start: "08:00"
36
+ work_end: "17:00"
37
+ wake_time_work: "07:00"
38
+ wake_time_off: "09:00"
39
+ quiet_hours:
40
+ start: 22
41
+ end: 7
42
+
43
+ # === SEARCH ===
44
+ search:
45
+ provider: "tavily"
46
+ tavily_api_key: "" # Can also go in the top-level tavily_api_key
47
+
48
+ # === STORAGE ===
49
+ storage:
50
+ photos_path: "D:\\TETHR Photos"
51
+ inbox_dir: "inbox"
@@ -0,0 +1,2 @@
1
+ """lulabell_engine — Standalone identity engine package."""
2
+ from lulabell_engine.pots_manager import start_pots, stop_pots, is_running
@@ -0,0 +1,2 @@
1
+ """ActionCore — Task Execution Agent."""
2
+ __version__ = "0.1.0"
@@ -0,0 +1,269 @@
1
+ """
2
+ api.py — FastAPI server for ActionCore (port 8002).
3
+
4
+ Endpoints:
5
+ GET /health — liveness check
6
+ GET /status — queue status + recent task history
7
+ GET /tools — list available tools
8
+ POST /task — submit a task {type, params}
9
+ POST /task/plan — plan a task (returns steps, no execution)
10
+ POST /task/execute — execute a pre-built plan
11
+ POST /task/run — plan + execute in one call
12
+ GET /task/{id}/status — status of a specific task by id
13
+ POST /diagnose — run full system diagnosis
14
+ """
15
+ import logging
16
+ from typing import Any
17
+
18
+ from fastapi import FastAPI, HTTPException, Request
19
+ from pydantic import BaseModel
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+ app = FastAPI(title="ActionCore", version="0.2.0")
24
+ # app.state.core is set by cli.py before the server starts
25
+
26
+ # ── Valid task types ──────────────────────────────────────────────────────────
27
+
28
+ _VALID_TYPES = {
29
+ "email_send",
30
+ "file_store",
31
+ "file_retrieve",
32
+ "system_status",
33
+ "llm_query",
34
+ "run_plan",
35
+ "diagnose_tethr",
36
+ "fix_collector",
37
+ "update_tethr",
38
+ "self_repair",
39
+ }
40
+
41
+
42
+ # ── Request models ────────────────────────────────────────────────────────────
43
+
44
+ class TaskRequest(BaseModel):
45
+ type: str
46
+ params: dict[str, Any] = {}
47
+
48
+
49
+ class PlanRequest(BaseModel):
50
+ description: str
51
+ stop_on_failure: bool = True
52
+
53
+
54
+ class StepDict(BaseModel):
55
+ action: str
56
+ tool: str
57
+ params: dict[str, Any] = {}
58
+ expected_result: str = ""
59
+ stop_on_failure: bool = True
60
+
61
+
62
+ class ExecuteRequest(BaseModel):
63
+ description: str = ""
64
+ steps: list[StepDict]
65
+ stop_on_failure: bool = True
66
+
67
+
68
+ class RunRequest(BaseModel):
69
+ description: str
70
+ stop_on_failure: bool = True
71
+ plan_only: bool = False
72
+
73
+
74
+ # ── Helpers ───────────────────────────────────────────────────────────────────
75
+
76
+ def _get_core(request: Request):
77
+ core = request.app.state.core
78
+ if core is None:
79
+ raise HTTPException(503, "Core not initialised")
80
+ return core
81
+
82
+
83
+ # ── Endpoints ─────────────────────────────────────────────────────────────────
84
+
85
+ @app.get("/health")
86
+ def health():
87
+ cfg = getattr(app.state, "config", {})
88
+ name = cfg.get("agent_name", "ActionCore")
89
+ return {"status": "ok", "agent": name, "version": "0.2.0"}
90
+
91
+
92
+ @app.get("/status")
93
+ def get_status(request: Request):
94
+ return _get_core(request).queue.get_status()
95
+
96
+
97
+ @app.get("/tools")
98
+ def list_tools():
99
+ """Return the list of available tools and their capabilities."""
100
+ return {
101
+ "tools": [
102
+ {
103
+ "name": "bash",
104
+ "desc": "Execute shell commands",
105
+ "params": ["command", "timeout", "allow_dangerous"],
106
+ },
107
+ {
108
+ "name": "files",
109
+ "desc": "Read, write, and edit files (within ALLOWED_PATHS)",
110
+ "params": ["action", "path", "content", "old_text", "new_text"],
111
+ },
112
+ {
113
+ "name": "docker",
114
+ "desc": "Manage Docker containers and compose stacks",
115
+ "params": ["action", "container", "image", "compose_file"],
116
+ },
117
+ {
118
+ "name": "systemd",
119
+ "desc": "Control system services (Linux systemctl / Windows sc)",
120
+ "params": ["action", "name"],
121
+ },
122
+ {
123
+ "name": "git",
124
+ "desc": "Git repository operations",
125
+ "params": ["action", "repo_path", "branch"],
126
+ },
127
+ {
128
+ "name": "config",
129
+ "desc": "Read/write YAML and JSON config files",
130
+ "params": ["action", "path", "key", "value"],
131
+ },
132
+ {
133
+ "name": "logs",
134
+ "desc": "Inspect log files",
135
+ "params": ["action", "path", "lines", "search"],
136
+ },
137
+ {
138
+ "name": "diagnose",
139
+ "desc": "System health diagnostics",
140
+ "params": ["check"],
141
+ "checks": ["tethr_health", "collectors", "disk", "memory", "ports", "processes", "full"],
142
+ },
143
+ ]
144
+ }
145
+
146
+
147
+ @app.post("/task")
148
+ def submit_task(req: TaskRequest, request: Request):
149
+ """Submit a background task to the ActionCore queue."""
150
+ core = _get_core(request)
151
+
152
+ if req.type not in _VALID_TYPES:
153
+ raise HTTPException(
154
+ 400,
155
+ f"Unknown task type {req.type!r}. Valid: {sorted(_VALID_TYPES)}",
156
+ )
157
+
158
+ task = core.queue.submit(req.type, req.params)
159
+ logger.info("[api] task submitted id=%s type=%s", task.id, task.type)
160
+ return {"task_id": task.id, "status": task.status, "type": task.type}
161
+
162
+
163
+ @app.post("/task/plan")
164
+ def plan_task(req: PlanRequest):
165
+ """
166
+ Plan a task and return the ordered steps — does NOT execute.
167
+ Use POST /task/run to plan + execute.
168
+ """
169
+ try:
170
+ from lulabell_engine.actioncore.planner import plan_task as _plan
171
+ steps = _plan(req.description)
172
+ return {
173
+ "description": req.description,
174
+ "steps": [s.to_dict() for s in steps],
175
+ "step_count": len(steps),
176
+ }
177
+ except Exception as exc:
178
+ raise HTTPException(500, str(exc))
179
+
180
+
181
+ @app.post("/task/execute")
182
+ def execute_plan(req: ExecuteRequest):
183
+ """Execute a pre-built list of steps (from /task/plan or hand-crafted)."""
184
+ try:
185
+ from lulabell_engine.actioncore.planner import Step
186
+ from lulabell_engine.actioncore.executor import execute_plan as _exec
187
+ from lulabell_engine.actioncore.validator import validate_task
188
+
189
+ steps = [Step.from_dict(s.dict()) for s in req.steps]
190
+ result = _exec(steps, task_description=req.description,
191
+ stop_on_failure=req.stop_on_failure)
192
+ val = validate_task(req.description, result)
193
+
194
+ return {
195
+ **result.to_dict(),
196
+ "validation": val.to_dict(),
197
+ }
198
+ except Exception as exc:
199
+ raise HTTPException(500, str(exc))
200
+
201
+
202
+ @app.post("/task/run")
203
+ def run_task(req: RunRequest):
204
+ """Plan and execute a task description in one call."""
205
+ try:
206
+ from lulabell_engine.actioncore.planner import plan_task as _plan
207
+ from lulabell_engine.actioncore.executor import execute_plan as _exec
208
+ from lulabell_engine.actioncore.validator import validate_task
209
+
210
+ steps = _plan(req.description)
211
+
212
+ if req.plan_only:
213
+ return {
214
+ "description": req.description,
215
+ "steps": [s.to_dict() for s in steps],
216
+ "step_count": len(steps),
217
+ "executed": False,
218
+ }
219
+
220
+ result = _exec(steps, task_description=req.description,
221
+ stop_on_failure=req.stop_on_failure)
222
+ val = validate_task(req.description, result)
223
+
224
+ return {
225
+ **result.to_dict(),
226
+ "validation": val.to_dict(),
227
+ "executed": True,
228
+ }
229
+ except Exception as exc:
230
+ raise HTTPException(500, str(exc))
231
+
232
+
233
+ @app.get("/task/{task_id}/status")
234
+ def task_status(task_id: str, request: Request):
235
+ """Get the current status of a queued/completed task by id."""
236
+ core = _get_core(request)
237
+ for task in core.queue._history:
238
+ if task.id == task_id:
239
+ return task.to_dict()
240
+ # Check if it's still in the queue (pending)
241
+ raise HTTPException(404, f"Task {task_id!r} not found")
242
+
243
+
244
+ @app.post("/diagnose")
245
+ def diagnose():
246
+ """Run a full system diagnosis and return the report."""
247
+ try:
248
+ from lulabell_engine.actioncore.tools.diagnose import full_diagnosis
249
+ report = full_diagnosis()
250
+
251
+ # High-level summary
252
+ issues = []
253
+ if not report["tethr"].get("server_up"):
254
+ issues.append("LulaBell server not responding")
255
+ silent = report["collectors"].get("silent", [])
256
+ if silent:
257
+ issues.append(f"Silent collectors: {', '.join(silent)}")
258
+ for part in report["disk"].get("low_space", []):
259
+ issues.append(f"Low disk space: {part}")
260
+ if report["memory"].get("low_memory"):
261
+ issues.append(f"High RAM usage: {report['memory']['ram_pct_used']:.0f}%")
262
+
263
+ return {
264
+ "healthy": len(issues) == 0,
265
+ "issues": issues,
266
+ "report": report,
267
+ }
268
+ except Exception as exc:
269
+ raise HTTPException(500, str(exc))