@agentikos/omega-os 0.1.0 → 0.19.5

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 (379) hide show
  1. package/README.md +56 -14
  2. package/bootstrap/lib/__pycache__/claude-code-settings.cpython-313.pyc +0 -0
  3. package/bootstrap/lib/__pycache__/llm-clis.cpython-313.pyc +0 -0
  4. package/bootstrap/lib/__pycache__/manifest-helpers.cpython-313.pyc +0 -0
  5. package/bootstrap/lib/claude-code-settings.py +176 -0
  6. package/bootstrap/lib/common.sh +457 -1
  7. package/bootstrap/lib/llm-clis.py +341 -0
  8. package/bootstrap/lib/manifest-helpers.py +384 -0
  9. package/bootstrap/lib/steps.sh +1000 -26
  10. package/bootstrap/manifest.example.yaml +93 -2
  11. package/bootstrap/templates/aisb/CLAUDE.md +305 -0
  12. package/bootstrap/templates/aisb/architect.md +204 -0
  13. package/bootstrap/templates/aisb/checkers/CLAUDE.md +9 -0
  14. package/bootstrap/templates/aisb/checkers/checker-architect.md +151 -0
  15. package/bootstrap/templates/aisb/checkers/checker-common.md +171 -0
  16. package/bootstrap/templates/aisb/checkers/checker-construct.md +129 -0
  17. package/bootstrap/templates/aisb/checkers/checker-keymaker.md +204 -0
  18. package/bootstrap/templates/aisb/checkers/checker-link.md +205 -0
  19. package/bootstrap/templates/aisb/checkers/checker-merovingian.md +219 -0
  20. package/bootstrap/templates/aisb/checkers/checker-morpheus.md +211 -0
  21. package/bootstrap/templates/aisb/checkers/checker-neo.md +177 -0
  22. package/bootstrap/templates/aisb/checkers/checker-niobe.md +156 -0
  23. package/bootstrap/templates/aisb/checkers/checker-oracle.md +164 -0
  24. package/bootstrap/templates/aisb/checkers/checker-seraph.md +187 -0
  25. package/bootstrap/templates/aisb/checkers/checker-smith.md +195 -0
  26. package/bootstrap/templates/aisb/checkers/checker-zion.md +113 -0
  27. package/bootstrap/templates/aisb/construct.md +135 -0
  28. package/bootstrap/templates/aisb/keymaker.md +227 -0
  29. package/bootstrap/templates/aisb/link.md +170 -0
  30. package/bootstrap/templates/aisb/lmc-protocol.md +57 -0
  31. package/bootstrap/templates/aisb/merovingian.md +159 -0
  32. package/bootstrap/templates/aisb/morpheus.md +243 -0
  33. package/bootstrap/templates/aisb/neo.md +147 -0
  34. package/bootstrap/templates/aisb/niobe.md +197 -0
  35. package/bootstrap/templates/aisb/oracle.md +244 -0
  36. package/bootstrap/templates/aisb/protocols/handoff-templates.md +204 -0
  37. package/bootstrap/templates/aisb/protocols/shared-protocol.md +248 -0
  38. package/bootstrap/templates/aisb/pythia.md +153 -0
  39. package/bootstrap/templates/aisb/seraph.md +315 -0
  40. package/bootstrap/templates/aisb/smith.md +202 -0
  41. package/bootstrap/templates/aisb/zion.md +172 -0
  42. package/bootstrap/templates/autonomous/audit-patrol.yaml +41 -0
  43. package/bootstrap/templates/autonomous/smith-reflect.yaml +43 -0
  44. package/bootstrap/templates/autonomous/ssh-key-rotate.yaml +46 -0
  45. package/bootstrap/templates/autonomous/support-agent.yaml +38 -0
  46. package/docs/AUDITS.md +85 -0
  47. package/docs/COMPLETION-PLAN.md +48 -0
  48. package/docs/GAP-ANALYSIS.md +214 -0
  49. package/docs/INSTALL.md +47 -9
  50. package/docs/MCP-AND-PLUGINS.md +31 -4
  51. package/docs/SIMULATION.md +171 -0
  52. package/docs/simulate.sh +211 -0
  53. package/install.sh +164 -17
  54. package/omega/Agentik_Engine/README.md +27 -10
  55. package/omega/Agentik_Engine/omega_engine/__init__.py +212 -2
  56. package/omega/Agentik_Engine/omega_engine/__pycache__/__init__.cpython-313.pyc +0 -0
  57. package/omega/Agentik_Engine/omega_engine/__pycache__/account.cpython-313.pyc +0 -0
  58. package/omega/Agentik_Engine/omega_engine/__pycache__/agent_messages.cpython-313.pyc +0 -0
  59. package/omega/Agentik_Engine/omega_engine/__pycache__/aisb_chat.cpython-313.pyc +0 -0
  60. package/omega/Agentik_Engine/omega_engine/__pycache__/audit_diff.cpython-313.pyc +0 -0
  61. package/omega/Agentik_Engine/omega_engine/__pycache__/audit_gate.cpython-313.pyc +0 -0
  62. package/omega/Agentik_Engine/omega_engine/__pycache__/auto_update.cpython-313.pyc +0 -0
  63. package/omega/Agentik_Engine/omega_engine/__pycache__/autonomous.cpython-313.pyc +0 -0
  64. package/omega/Agentik_Engine/omega_engine/__pycache__/backup.cpython-313.pyc +0 -0
  65. package/omega/Agentik_Engine/omega_engine/__pycache__/cadence.cpython-313.pyc +0 -0
  66. package/omega/Agentik_Engine/omega_engine/__pycache__/classifier.cpython-313.pyc +0 -0
  67. package/omega/Agentik_Engine/omega_engine/__pycache__/cleanup.cpython-313.pyc +0 -0
  68. package/omega/Agentik_Engine/omega_engine/__pycache__/cli.cpython-313.pyc +0 -0
  69. package/omega/Agentik_Engine/omega_engine/__pycache__/completions.cpython-313.pyc +0 -0
  70. package/omega/Agentik_Engine/omega_engine/__pycache__/costs.cpython-313.pyc +0 -0
  71. package/omega/Agentik_Engine/omega_engine/__pycache__/done_signal.cpython-313.pyc +0 -0
  72. package/omega/Agentik_Engine/omega_engine/__pycache__/envelope.cpython-313.pyc +0 -0
  73. package/omega/Agentik_Engine/omega_engine/__pycache__/executor.cpython-313.pyc +0 -0
  74. package/omega/Agentik_Engine/omega_engine/__pycache__/handoff.cpython-313.pyc +0 -0
  75. package/omega/Agentik_Engine/omega_engine/__pycache__/hermes.cpython-313.pyc +0 -0
  76. package/omega/Agentik_Engine/omega_engine/__pycache__/hermes_bootstrap.cpython-313.pyc +0 -0
  77. package/omega/Agentik_Engine/omega_engine/__pycache__/hermes_desktop.cpython-313.pyc +0 -0
  78. package/omega/Agentik_Engine/omega_engine/__pycache__/learning.cpython-313.pyc +0 -0
  79. package/omega/Agentik_Engine/omega_engine/__pycache__/managed_agent.cpython-313.pyc +0 -0
  80. package/omega/Agentik_Engine/omega_engine/__pycache__/memory.cpython-313.pyc +0 -0
  81. package/omega/Agentik_Engine/omega_engine/__pycache__/menu.cpython-313.pyc +0 -0
  82. package/omega/Agentik_Engine/omega_engine/__pycache__/mission.cpython-313.pyc +0 -0
  83. package/omega/Agentik_Engine/omega_engine/__pycache__/plan.cpython-313.pyc +0 -0
  84. package/omega/Agentik_Engine/omega_engine/__pycache__/project.cpython-313.pyc +0 -0
  85. package/omega/Agentik_Engine/omega_engine/__pycache__/prompts.cpython-313.pyc +0 -0
  86. package/omega/Agentik_Engine/omega_engine/__pycache__/provider.cpython-313.pyc +0 -0
  87. package/omega/Agentik_Engine/omega_engine/__pycache__/prune.cpython-313.pyc +0 -0
  88. package/omega/Agentik_Engine/omega_engine/__pycache__/pursue.cpython-313.pyc +0 -0
  89. package/omega/Agentik_Engine/omega_engine/__pycache__/reducer.cpython-313.pyc +0 -0
  90. package/omega/Agentik_Engine/omega_engine/__pycache__/router.cpython-313.pyc +0 -0
  91. package/omega/Agentik_Engine/omega_engine/__pycache__/skill_routing.cpython-313.pyc +0 -0
  92. package/omega/Agentik_Engine/omega_engine/__pycache__/smoke.cpython-313.pyc +0 -0
  93. package/omega/Agentik_Engine/omega_engine/__pycache__/store.cpython-313.pyc +0 -0
  94. package/omega/Agentik_Engine/omega_engine/__pycache__/sync.cpython-313.pyc +0 -0
  95. package/omega/Agentik_Engine/omega_engine/__pycache__/telegram_history.cpython-313.pyc +0 -0
  96. package/omega/Agentik_Engine/omega_engine/__pycache__/tmux.cpython-313.pyc +0 -0
  97. package/omega/Agentik_Engine/omega_engine/__pycache__/tools.cpython-313.pyc +0 -0
  98. package/omega/Agentik_Engine/omega_engine/__pycache__/understand_anything.cpython-313.pyc +0 -0
  99. package/omega/Agentik_Engine/omega_engine/__pycache__/updater.cpython-313.pyc +0 -0
  100. package/omega/Agentik_Engine/omega_engine/__pycache__/validate.cpython-313.pyc +0 -0
  101. package/omega/Agentik_Engine/omega_engine/__pycache__/vault.cpython-313.pyc +0 -0
  102. package/omega/Agentik_Engine/omega_engine/__pycache__/webhooks.cpython-313.pyc +0 -0
  103. package/omega/Agentik_Engine/omega_engine/__pycache__/worker.cpython-313.pyc +0 -0
  104. package/omega/Agentik_Engine/omega_engine/account.py +502 -0
  105. package/omega/Agentik_Engine/omega_engine/agent_messages.py +167 -0
  106. package/omega/Agentik_Engine/omega_engine/aisb_chat.py +128 -0
  107. package/omega/Agentik_Engine/omega_engine/audit_diff.py +99 -0
  108. package/omega/Agentik_Engine/omega_engine/audit_gate.py +149 -0
  109. package/omega/Agentik_Engine/omega_engine/audits/__init__.py +60 -0
  110. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/__init__.cpython-313.pyc +0 -0
  111. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/batcher.cpython-313.pyc +0 -0
  112. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/dispatcher.cpython-313.pyc +0 -0
  113. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/generator.cpython-313.pyc +0 -0
  114. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/history.cpython-313.pyc +0 -0
  115. package/omega/Agentik_Engine/omega_engine/audits/__pycache__/pipeline.cpython-313.pyc +0 -0
  116. package/omega/Agentik_Engine/omega_engine/audits/batcher.py +218 -0
  117. package/omega/Agentik_Engine/omega_engine/audits/dispatcher.py +92 -0
  118. package/omega/Agentik_Engine/omega_engine/audits/generator.py +234 -0
  119. package/omega/Agentik_Engine/omega_engine/audits/history.py +168 -0
  120. package/omega/Agentik_Engine/omega_engine/audits/pipeline.py +198 -0
  121. package/omega/Agentik_Engine/omega_engine/auto_update.py +339 -0
  122. package/omega/Agentik_Engine/omega_engine/autonomous.py +538 -0
  123. package/omega/Agentik_Engine/omega_engine/backup.py +215 -0
  124. package/omega/Agentik_Engine/omega_engine/cadence.py +158 -0
  125. package/omega/Agentik_Engine/omega_engine/classifier.py +215 -0
  126. package/omega/Agentik_Engine/omega_engine/cleanup.py +673 -0
  127. package/omega/Agentik_Engine/omega_engine/cli.py +4564 -56
  128. package/omega/Agentik_Engine/omega_engine/completions.py +260 -0
  129. package/omega/Agentik_Engine/omega_engine/costs.py +100 -0
  130. package/omega/Agentik_Engine/omega_engine/daemons/__init__.py +14 -0
  131. package/omega/Agentik_Engine/omega_engine/daemons/__pycache__/__init__.cpython-313.pyc +0 -0
  132. package/omega/Agentik_Engine/omega_engine/daemons/__pycache__/autonomous.cpython-313.pyc +0 -0
  133. package/omega/Agentik_Engine/omega_engine/daemons/__pycache__/engine.cpython-313.pyc +0 -0
  134. package/omega/Agentik_Engine/omega_engine/daemons/__pycache__/telegram.cpython-313.pyc +0 -0
  135. package/omega/Agentik_Engine/omega_engine/daemons/autonomous.py +56 -0
  136. package/omega/Agentik_Engine/omega_engine/daemons/engine.py +236 -0
  137. package/omega/Agentik_Engine/omega_engine/daemons/telegram.py +315 -0
  138. package/omega/Agentik_Engine/omega_engine/done_signal.py +154 -0
  139. package/omega/Agentik_Engine/omega_engine/educators/__init__.py +51 -0
  140. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/__init__.cpython-313.pyc +0 -0
  141. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/artifact.cpython-313.pyc +0 -0
  142. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/automation.cpython-313.pyc +0 -0
  143. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/base.cpython-313.pyc +0 -0
  144. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/claudecode.cpython-313.pyc +0 -0
  145. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/connection.cpython-313.pyc +0 -0
  146. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/coworker.cpython-313.pyc +0 -0
  147. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/loop.cpython-313.pyc +0 -0
  148. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/prompt.cpython-313.pyc +0 -0
  149. package/omega/Agentik_Engine/omega_engine/educators/__pycache__/skill.cpython-313.pyc +0 -0
  150. package/omega/Agentik_Engine/omega_engine/educators/artifact.py +65 -0
  151. package/omega/Agentik_Engine/omega_engine/educators/automation.py +76 -0
  152. package/omega/Agentik_Engine/omega_engine/educators/base.py +327 -0
  153. package/omega/Agentik_Engine/omega_engine/educators/claudecode.py +71 -0
  154. package/omega/Agentik_Engine/omega_engine/educators/connection.py +75 -0
  155. package/omega/Agentik_Engine/omega_engine/educators/coworker.py +68 -0
  156. package/omega/Agentik_Engine/omega_engine/educators/loop.py +82 -0
  157. package/omega/Agentik_Engine/omega_engine/educators/prompt.py +68 -0
  158. package/omega/Agentik_Engine/omega_engine/educators/skill.py +69 -0
  159. package/omega/Agentik_Engine/omega_engine/envelope.py +219 -0
  160. package/omega/Agentik_Engine/omega_engine/executor.py +195 -16
  161. package/omega/Agentik_Engine/omega_engine/genesis/__init__.py +134 -0
  162. package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/__init__.cpython-313.pyc +0 -0
  163. package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/orchestrator.cpython-313.pyc +0 -0
  164. package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/phases.cpython-313.pyc +0 -0
  165. package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/stack.cpython-313.pyc +0 -0
  166. package/omega/Agentik_Engine/omega_engine/genesis/__pycache__/state.cpython-313.pyc +0 -0
  167. package/omega/Agentik_Engine/omega_engine/genesis/orchestrator.py +262 -0
  168. package/omega/Agentik_Engine/omega_engine/genesis/phases.py +950 -0
  169. package/omega/Agentik_Engine/omega_engine/genesis/stack.py +324 -0
  170. package/omega/Agentik_Engine/omega_engine/genesis/state.py +353 -0
  171. package/omega/Agentik_Engine/omega_engine/handoff.py +459 -0
  172. package/omega/Agentik_Engine/omega_engine/hermes.py +426 -0
  173. package/omega/Agentik_Engine/omega_engine/hermes_bootstrap.py +382 -0
  174. package/omega/Agentik_Engine/omega_engine/hermes_desktop.py +469 -0
  175. package/omega/Agentik_Engine/omega_engine/integrations/__init__.py +30 -0
  176. package/omega/Agentik_Engine/omega_engine/integrations/__pycache__/__init__.cpython-313.pyc +0 -0
  177. package/omega/Agentik_Engine/omega_engine/integrations/__pycache__/graphify.cpython-313.pyc +0 -0
  178. package/omega/Agentik_Engine/omega_engine/integrations/graphify.py +234 -0
  179. package/omega/Agentik_Engine/omega_engine/learning.py +268 -0
  180. package/omega/Agentik_Engine/omega_engine/managed_agent.py +467 -0
  181. package/omega/Agentik_Engine/omega_engine/memory.py +271 -0
  182. package/omega/Agentik_Engine/omega_engine/menu.py +1065 -0
  183. package/omega/Agentik_Engine/omega_engine/migrations/__init__.py +144 -0
  184. package/omega/Agentik_Engine/omega_engine/migrations/__pycache__/__init__.cpython-313.pyc +0 -0
  185. package/omega/Agentik_Engine/omega_engine/migrations/__pycache__/v0_14_0.cpython-313.pyc +0 -0
  186. package/omega/Agentik_Engine/omega_engine/migrations/v0_14_0.py +29 -0
  187. package/omega/Agentik_Engine/omega_engine/mission.py +29 -14
  188. package/omega/Agentik_Engine/omega_engine/plan.py +846 -0
  189. package/omega/Agentik_Engine/omega_engine/prompts.py +158 -0
  190. package/omega/Agentik_Engine/omega_engine/provider.py +408 -13
  191. package/omega/Agentik_Engine/omega_engine/prune.py +151 -0
  192. package/omega/Agentik_Engine/omega_engine/pursue.py +205 -0
  193. package/omega/Agentik_Engine/omega_engine/rag/__init__.py +21 -0
  194. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/__init__.cpython-313.pyc +0 -0
  195. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/agentic.cpython-313.pyc +0 -0
  196. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/base.cpython-313.pyc +0 -0
  197. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/corrective.cpython-313.pyc +0 -0
  198. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/graph.cpython-313.pyc +0 -0
  199. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/hybrid.cpython-313.pyc +0 -0
  200. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/multimodal.cpython-313.pyc +0 -0
  201. package/omega/Agentik_Engine/omega_engine/rag/__pycache__/router.cpython-313.pyc +0 -0
  202. package/omega/Agentik_Engine/omega_engine/rag/agentic.py +83 -0
  203. package/omega/Agentik_Engine/omega_engine/rag/base.py +42 -0
  204. package/omega/Agentik_Engine/omega_engine/rag/corrective.py +119 -0
  205. package/omega/Agentik_Engine/omega_engine/rag/graph.py +169 -0
  206. package/omega/Agentik_Engine/omega_engine/rag/hybrid.py +205 -0
  207. package/omega/Agentik_Engine/omega_engine/rag/multimodal.py +136 -0
  208. package/omega/Agentik_Engine/omega_engine/rag/router.py +110 -0
  209. package/omega/Agentik_Engine/omega_engine/reducer.py +21 -3
  210. package/omega/Agentik_Engine/omega_engine/router.py +28 -0
  211. package/omega/Agentik_Engine/omega_engine/skill_discovery/__init__.py +48 -0
  212. package/omega/Agentik_Engine/omega_engine/skill_discovery/__pycache__/__init__.cpython-313.pyc +0 -0
  213. package/omega/Agentik_Engine/omega_engine/skill_discovery/__pycache__/auditor.cpython-313.pyc +0 -0
  214. package/omega/Agentik_Engine/omega_engine/skill_discovery/__pycache__/finder.cpython-313.pyc +0 -0
  215. package/omega/Agentik_Engine/omega_engine/skill_discovery/__pycache__/installer.cpython-313.pyc +0 -0
  216. package/omega/Agentik_Engine/omega_engine/skill_discovery/__pycache__/marketplaces.cpython-313.pyc +0 -0
  217. package/omega/Agentik_Engine/omega_engine/skill_discovery/auditor.py +232 -0
  218. package/omega/Agentik_Engine/omega_engine/skill_discovery/finder.py +94 -0
  219. package/omega/Agentik_Engine/omega_engine/skill_discovery/installer.py +129 -0
  220. package/omega/Agentik_Engine/omega_engine/skill_discovery/marketplaces.py +80 -0
  221. package/omega/Agentik_Engine/omega_engine/skill_routing.py +388 -0
  222. package/omega/Agentik_Engine/omega_engine/smoke.py +81 -0
  223. package/omega/Agentik_Engine/omega_engine/store.py +132 -25
  224. package/omega/Agentik_Engine/omega_engine/sync.py +445 -0
  225. package/omega/Agentik_Engine/omega_engine/telegram_history.py +260 -0
  226. package/omega/Agentik_Engine/omega_engine/tmux.py +526 -0
  227. package/omega/Agentik_Engine/omega_engine/tools.py +272 -0
  228. package/omega/Agentik_Engine/omega_engine/understand_anything.py +275 -0
  229. package/omega/Agentik_Engine/omega_engine/updater.py +70 -0
  230. package/omega/Agentik_Engine/omega_engine/validate.py +186 -0
  231. package/omega/Agentik_Engine/omega_engine/vault.py +342 -0
  232. package/omega/Agentik_Engine/omega_engine/webhooks.py +262 -0
  233. package/omega/Agentik_Engine/omega_engine/worker.py +526 -0
  234. package/omega/Agentik_Engine/pyproject.toml +1 -1
  235. package/omega/Agentik_Engine/tests/__pycache__/test_account.cpython-313-pytest-8.4.2.pyc +0 -0
  236. package/omega/Agentik_Engine/tests/__pycache__/test_account.cpython-313.pyc +0 -0
  237. package/omega/Agentik_Engine/tests/__pycache__/test_adversarial.cpython-313-pytest-8.4.2.pyc +0 -0
  238. package/omega/Agentik_Engine/tests/__pycache__/test_adversarial.cpython-313.pyc +0 -0
  239. package/omega/Agentik_Engine/tests/__pycache__/test_agents_envelope.cpython-313-pytest-8.4.2.pyc +0 -0
  240. package/omega/Agentik_Engine/tests/__pycache__/test_agents_envelope.cpython-313.pyc +0 -0
  241. package/omega/Agentik_Engine/tests/__pycache__/test_audit_arsenal.cpython-313-pytest-8.4.2.pyc +0 -0
  242. package/omega/Agentik_Engine/tests/__pycache__/test_audits_pipeline.cpython-313-pytest-8.4.2.pyc +0 -0
  243. package/omega/Agentik_Engine/tests/__pycache__/test_audits_pipeline.cpython-313.pyc +0 -0
  244. package/omega/Agentik_Engine/tests/__pycache__/test_auto_update_and_migrations.cpython-313-pytest-8.4.2.pyc +0 -0
  245. package/omega/Agentik_Engine/tests/__pycache__/test_auto_update_and_migrations.cpython-313.pyc +0 -0
  246. package/omega/Agentik_Engine/tests/__pycache__/test_autonomous.cpython-313-pytest-8.4.2.pyc +0 -0
  247. package/omega/Agentik_Engine/tests/__pycache__/test_autonomous.cpython-313.pyc +0 -0
  248. package/omega/Agentik_Engine/tests/__pycache__/test_educators.cpython-313-pytest-8.4.2.pyc +0 -0
  249. package/omega/Agentik_Engine/tests/__pycache__/test_educators.cpython-313.pyc +0 -0
  250. package/omega/Agentik_Engine/tests/__pycache__/test_executor.cpython-313-pytest-8.4.2.pyc +0 -0
  251. package/omega/Agentik_Engine/tests/__pycache__/test_genesis_and_plan.cpython-313-pytest-8.4.2.pyc +0 -0
  252. package/omega/Agentik_Engine/tests/__pycache__/test_genesis_and_plan.cpython-313.pyc +0 -0
  253. package/omega/Agentik_Engine/tests/__pycache__/test_graphify.cpython-313-pytest-8.4.2.pyc +0 -0
  254. package/omega/Agentik_Engine/tests/__pycache__/test_graphify.cpython-313.pyc +0 -0
  255. package/omega/Agentik_Engine/tests/__pycache__/test_handoff.cpython-313-pytest-8.4.2.pyc +0 -0
  256. package/omega/Agentik_Engine/tests/__pycache__/test_handoff.cpython-313.pyc +0 -0
  257. package/omega/Agentik_Engine/tests/__pycache__/test_hermes_and_ua.cpython-313-pytest-8.4.2.pyc +0 -0
  258. package/omega/Agentik_Engine/tests/__pycache__/test_hermes_and_ua.cpython-313.pyc +0 -0
  259. package/omega/Agentik_Engine/tests/__pycache__/test_hermes_bootstrap_and_desktop.cpython-313-pytest-8.4.2.pyc +0 -0
  260. package/omega/Agentik_Engine/tests/__pycache__/test_hermes_bootstrap_and_desktop.cpython-313.pyc +0 -0
  261. package/omega/Agentik_Engine/tests/__pycache__/test_install_steps.cpython-313-pytest-8.4.2.pyc +0 -0
  262. package/omega/Agentik_Engine/tests/__pycache__/test_install_steps.cpython-313.pyc +0 -0
  263. package/omega/Agentik_Engine/tests/__pycache__/test_install_ux.cpython-313-pytest-8.4.2.pyc +0 -0
  264. package/omega/Agentik_Engine/tests/__pycache__/test_install_ux.cpython-313.pyc +0 -0
  265. package/omega/Agentik_Engine/tests/__pycache__/test_installer_wiring.cpython-313-pytest-8.4.2.pyc +0 -0
  266. package/omega/Agentik_Engine/tests/__pycache__/test_installer_wiring.cpython-313.pyc +0 -0
  267. package/omega/Agentik_Engine/tests/__pycache__/test_intelligence.cpython-313-pytest-8.4.2.pyc +0 -0
  268. package/omega/Agentik_Engine/tests/__pycache__/test_intelligence.cpython-313.pyc +0 -0
  269. package/omega/Agentik_Engine/tests/__pycache__/test_llm_clis_and_uninstall.cpython-313-pytest-8.4.2.pyc +0 -0
  270. package/omega/Agentik_Engine/tests/__pycache__/test_llm_clis_and_uninstall.cpython-313.pyc +0 -0
  271. package/omega/Agentik_Engine/tests/__pycache__/test_managed_agent.cpython-313-pytest-8.4.2.pyc +0 -0
  272. package/omega/Agentik_Engine/tests/__pycache__/test_managed_agent.cpython-313.pyc +0 -0
  273. package/omega/Agentik_Engine/tests/__pycache__/test_max_provider_and_menu.cpython-313-pytest-8.4.2.pyc +0 -0
  274. package/omega/Agentik_Engine/tests/__pycache__/test_max_provider_and_menu.cpython-313.pyc +0 -0
  275. package/omega/Agentik_Engine/tests/__pycache__/test_menu_coverage.cpython-313-pytest-8.4.2.pyc +0 -0
  276. package/omega/Agentik_Engine/tests/__pycache__/test_menu_coverage.cpython-313.pyc +0 -0
  277. package/omega/Agentik_Engine/tests/__pycache__/test_mission.cpython-313-pytest-8.4.2.pyc +0 -0
  278. package/omega/Agentik_Engine/tests/__pycache__/test_progress.cpython-313-pytest-8.4.2.pyc +0 -0
  279. package/omega/Agentik_Engine/tests/__pycache__/test_project.cpython-313-pytest-8.4.2.pyc +0 -0
  280. package/omega/Agentik_Engine/tests/__pycache__/test_pursue_cadence.cpython-313-pytest-8.4.2.pyc +0 -0
  281. package/omega/Agentik_Engine/tests/__pycache__/test_pursue_cadence.cpython-313.pyc +0 -0
  282. package/omega/Agentik_Engine/tests/__pycache__/test_rag.cpython-313-pytest-8.4.2.pyc +0 -0
  283. package/omega/Agentik_Engine/tests/__pycache__/test_rag.cpython-313.pyc +0 -0
  284. package/omega/Agentik_Engine/tests/__pycache__/test_reducer.cpython-313-pytest-8.4.2.pyc +0 -0
  285. package/omega/Agentik_Engine/tests/__pycache__/test_report.cpython-313-pytest-8.4.2.pyc +0 -0
  286. package/omega/Agentik_Engine/tests/__pycache__/test_role_aliases_and_ssot.cpython-313-pytest-8.4.2.pyc +0 -0
  287. package/omega/Agentik_Engine/tests/__pycache__/test_role_aliases_and_ssot.cpython-313.pyc +0 -0
  288. package/omega/Agentik_Engine/tests/__pycache__/test_skill_discovery_and_gate.cpython-313-pytest-8.4.2.pyc +0 -0
  289. package/omega/Agentik_Engine/tests/__pycache__/test_skill_discovery_and_gate.cpython-313.pyc +0 -0
  290. package/omega/Agentik_Engine/tests/__pycache__/test_skill_power.cpython-313-pytest-8.4.2.pyc +0 -0
  291. package/omega/Agentik_Engine/tests/__pycache__/test_skill_power.cpython-313.pyc +0 -0
  292. package/omega/Agentik_Engine/tests/__pycache__/test_skill_routing.cpython-313-pytest-8.4.2.pyc +0 -0
  293. package/omega/Agentik_Engine/tests/__pycache__/test_skill_routing.cpython-313.pyc +0 -0
  294. package/omega/Agentik_Engine/tests/__pycache__/test_snapshot_partial.cpython-313-pytest-8.4.2.pyc +0 -0
  295. package/omega/Agentik_Engine/tests/__pycache__/test_snapshot_partial.cpython-313.pyc +0 -0
  296. package/omega/Agentik_Engine/tests/__pycache__/test_telegram_history.cpython-313-pytest-8.4.2.pyc +0 -0
  297. package/omega/Agentik_Engine/tests/__pycache__/test_telegram_history.cpython-313.pyc +0 -0
  298. package/omega/Agentik_Engine/tests/__pycache__/test_tmux_and_aisb_chat.cpython-313-pytest-8.4.2.pyc +0 -0
  299. package/omega/Agentik_Engine/tests/__pycache__/test_tmux_and_aisb_chat.cpython-313.pyc +0 -0
  300. package/omega/Agentik_Engine/tests/__pycache__/test_tools_and_sync.cpython-313-pytest-8.4.2.pyc +0 -0
  301. package/omega/Agentik_Engine/tests/__pycache__/test_tools_and_sync.cpython-313.pyc +0 -0
  302. package/omega/Agentik_Engine/tests/__pycache__/test_v06_features.cpython-313-pytest-8.4.2.pyc +0 -0
  303. package/omega/Agentik_Engine/tests/__pycache__/test_v06_features.cpython-313.pyc +0 -0
  304. package/omega/Agentik_Engine/tests/__pycache__/test_vault.cpython-313-pytest-8.4.2.pyc +0 -0
  305. package/omega/Agentik_Engine/tests/__pycache__/test_vault.cpython-313.pyc +0 -0
  306. package/omega/Agentik_Engine/tests/__pycache__/test_webhooks_and_readiness.cpython-313-pytest-8.4.2.pyc +0 -0
  307. package/omega/Agentik_Engine/tests/__pycache__/test_webhooks_and_readiness.cpython-313.pyc +0 -0
  308. package/omega/Agentik_Engine/tests/__pycache__/test_worker_and_cleanup.cpython-313-pytest-8.4.2.pyc +0 -0
  309. package/omega/Agentik_Engine/tests/__pycache__/test_worker_and_cleanup.cpython-313.pyc +0 -0
  310. package/omega/Agentik_Engine/tests/test_account.py +338 -0
  311. package/omega/Agentik_Engine/tests/test_adversarial.py +351 -0
  312. package/omega/Agentik_Engine/tests/test_agents_envelope.py +274 -0
  313. package/omega/Agentik_Engine/tests/test_audits_pipeline.py +348 -0
  314. package/omega/Agentik_Engine/tests/test_auto_update_and_migrations.py +394 -0
  315. package/omega/Agentik_Engine/tests/test_autonomous.py +361 -0
  316. package/omega/Agentik_Engine/tests/test_educators.py +233 -0
  317. package/omega/Agentik_Engine/tests/test_genesis_and_plan.py +573 -0
  318. package/omega/Agentik_Engine/tests/test_graphify.py +190 -0
  319. package/omega/Agentik_Engine/tests/test_handoff.py +311 -0
  320. package/omega/Agentik_Engine/tests/test_hermes_and_ua.py +387 -0
  321. package/omega/Agentik_Engine/tests/test_hermes_bootstrap_and_desktop.py +358 -0
  322. package/omega/Agentik_Engine/tests/test_install_steps.py +359 -0
  323. package/omega/Agentik_Engine/tests/test_install_ux.py +151 -0
  324. package/omega/Agentik_Engine/tests/test_installer_wiring.py +496 -0
  325. package/omega/Agentik_Engine/tests/test_intelligence.py +285 -0
  326. package/omega/Agentik_Engine/tests/test_llm_clis_and_uninstall.py +228 -0
  327. package/omega/Agentik_Engine/tests/test_managed_agent.py +363 -0
  328. package/omega/Agentik_Engine/tests/test_max_provider_and_menu.py +231 -0
  329. package/omega/Agentik_Engine/tests/test_menu_coverage.py +72 -0
  330. package/omega/Agentik_Engine/tests/test_pursue_cadence.py +217 -0
  331. package/omega/Agentik_Engine/tests/test_rag.py +287 -0
  332. package/omega/Agentik_Engine/tests/test_role_aliases_and_ssot.py +207 -0
  333. package/omega/Agentik_Engine/tests/test_skill_discovery_and_gate.py +337 -0
  334. package/omega/Agentik_Engine/tests/test_skill_power.py +259 -0
  335. package/omega/Agentik_Engine/tests/test_skill_routing.py +189 -0
  336. package/omega/Agentik_Engine/tests/test_snapshot_partial.py +172 -0
  337. package/omega/Agentik_Engine/tests/test_telegram_history.py +209 -0
  338. package/omega/Agentik_Engine/tests/test_tmux_and_aisb_chat.py +223 -0
  339. package/omega/Agentik_Engine/tests/test_tools_and_sync.py +312 -0
  340. package/omega/Agentik_Engine/tests/test_v06_features.py +370 -0
  341. package/omega/Agentik_Engine/tests/test_vault.py +173 -0
  342. package/omega/Agentik_Engine/tests/test_webhooks_and_readiness.py +277 -0
  343. package/omega/Agentik_Engine/tests/test_worker_and_cleanup.py +541 -0
  344. package/omega/Agentik_Extra/etc/secrets/.vault-key +3 -0
  345. package/omega/Agentik_Extra/etc/secrets/.vault-pub +1 -0
  346. package/omega/Agentik_Runtime/audits.db +0 -0
  347. package/omega/Agentik_SSOT/VERSION +1 -1
  348. package/omega/Agentik_SSOT/claude-plugins/claude-plugins.yaml +100 -0
  349. package/omega/Agentik_SSOT/docs/LAYERS.md +90 -0
  350. package/omega/Agentik_SSOT/docs/USER-JOURNEY.md +283 -0
  351. package/omega/Agentik_SSOT/marketplaces/design-discipline.yaml +86 -0
  352. package/omega/Agentik_SSOT/skills/a11yaudit/SKILL.md +161 -0
  353. package/omega/Agentik_SSOT/skills/apiaudit/SKILL.md +157 -0
  354. package/omega/Agentik_SSOT/skills/automationaudit/SKILL.md +161 -0
  355. package/omega/Agentik_SSOT/skills/cadence/SKILL.md +76 -0
  356. package/omega/Agentik_SSOT/skills/codeaudit/SKILL.md +153 -0
  357. package/omega/Agentik_SSOT/skills/copyaudit/SKILL.md +161 -0
  358. package/omega/Agentik_SSOT/skills/dataaudit/SKILL.md +157 -0
  359. package/omega/Agentik_SSOT/skills/debugaudit/SKILL.md +161 -0
  360. package/omega/Agentik_SSOT/skills/dispatch/SKILL.md +79 -0
  361. package/omega/Agentik_SSOT/skills/dxaudit/SKILL.md +161 -0
  362. package/omega/Agentik_SSOT/skills/featureaudit/SKILL.md +161 -0
  363. package/omega/Agentik_SSOT/skills/flowaudit/SKILL.md +165 -0
  364. package/omega/Agentik_SSOT/skills/genesis/SKILL.md +116 -0
  365. package/omega/Agentik_SSOT/skills/handoff/SKILL.md +117 -0
  366. package/omega/Agentik_SSOT/skills/logicaudit/SKILL.md +165 -0
  367. package/omega/Agentik_SSOT/skills/motionaudit/SKILL.md +165 -0
  368. package/omega/Agentik_SSOT/skills/perfaudit/SKILL.md +161 -0
  369. package/omega/Agentik_SSOT/skills/plan/SKILL.md +127 -0
  370. package/omega/Agentik_SSOT/skills/pursue/SKILL.md +68 -0
  371. package/omega/Agentik_SSOT/skills/rag-route.md +82 -0
  372. package/omega/Agentik_SSOT/skills/refontaudit/SKILL.md +165 -0
  373. package/omega/Agentik_SSOT/skills/retentionaudit/SKILL.md +165 -0
  374. package/omega/Agentik_SSOT/skills/secaudit/SKILL.md +157 -0
  375. package/omega/Agentik_SSOT/skills/seoaudit/SKILL.md +161 -0
  376. package/omega/Agentik_SSOT/skills/skill-auditor/SKILL.md +83 -0
  377. package/omega/Agentik_SSOT/skills/skill-finder/SKILL.md +116 -0
  378. package/omega/Agentik_SSOT/skills/uiuxaudit/SKILL.md +165 -0
  379. package/package.json +2 -2
@@ -0,0 +1,169 @@
1
+ """Graph retriever — entity-relation graph with depth-limited expansion.
2
+
3
+ Plain Python: dict-of-sets adjacency, typed edges. Persists to JSON. The
4
+ retrieval contract picks seed nodes from query tokens, expands `depth` hops,
5
+ and returns each visited node as a Document.
6
+
7
+ This is the "second strategy" in the multi-RAG router: when a query is
8
+ relational ("who works on X", "what depends on Y"), the graph wins over
9
+ hybrid.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ import re
15
+ from collections import defaultdict, deque
16
+ from pathlib import Path
17
+ from typing import Any, Iterable
18
+
19
+ from omega_engine.rag.base import Document, RetrievalResult
20
+
21
+
22
+ _TOKEN_RE = re.compile(r"[A-Za-z0-9_]+")
23
+
24
+
25
+ def _tokens(text: str) -> list[str]:
26
+ return [t.lower() for t in _TOKEN_RE.findall(text)]
27
+
28
+
29
+ class GraphRetriever:
30
+ """In-memory entity-relation graph with JSON persistence.
31
+
32
+ Edge tuples are `(neighbour, edge_type)`. The graph is undirected for
33
+ expansion — adding `(a, b, "depends_on")` makes `b` a neighbour of `a`
34
+ AND `a` a neighbour of `b`. The edge type travels with the neighbour so
35
+ the caller can filter on it.
36
+ """
37
+
38
+ strategy = "graph"
39
+
40
+ def __init__(self, json_path: str | Path | None = None) -> None:
41
+ self.json_path = str(json_path) if json_path is not None else None
42
+ self._adj: dict[str, set[tuple[str, str]]] = defaultdict(set)
43
+ self._node_text: dict[str, str] = {} # optional node text body
44
+ self._node_meta: dict[str, dict[str, Any]] = {}
45
+ if self.json_path and Path(self.json_path).exists():
46
+ self._load()
47
+
48
+ # ----- mutation -----
49
+
50
+ def add_node(
51
+ self,
52
+ node: str,
53
+ text: str | None = None,
54
+ metadata: dict[str, Any] | None = None,
55
+ ) -> None:
56
+ self._adj.setdefault(node, set())
57
+ if text is not None:
58
+ self._node_text[node] = text
59
+ if metadata is not None:
60
+ self._node_meta[node] = dict(metadata)
61
+
62
+ def add_edge(self, a: str, b: str, edge_type: str = "rel") -> None:
63
+ """Add an undirected typed edge between two nodes. Idempotent."""
64
+ self.add_node(a)
65
+ self.add_node(b)
66
+ self._adj[a].add((b, edge_type))
67
+ self._adj[b].add((a, edge_type))
68
+ if self.json_path:
69
+ self._save()
70
+
71
+ def neighbors(self, node: str, depth: int = 1) -> list[str]:
72
+ """BFS up to `depth` hops. Returns nodes in discovery order, excluding
73
+ the seed itself."""
74
+ if depth <= 0 or node not in self._adj:
75
+ return []
76
+ seen: set[str] = {node}
77
+ out: list[str] = []
78
+ q: deque[tuple[str, int]] = deque([(node, 0)])
79
+ while q:
80
+ cur, d = q.popleft()
81
+ if d == depth:
82
+ continue
83
+ for nbr, _etype in self._adj[cur]:
84
+ if nbr in seen:
85
+ continue
86
+ seen.add(nbr)
87
+ out.append(nbr)
88
+ q.append((nbr, d + 1))
89
+ return out
90
+
91
+ # ----- retrieval -----
92
+
93
+ def retrieve(self, query: str, k: int = 5, depth: int = 2) -> RetrievalResult:
94
+ """Pick seeds whose name overlaps a query token; expand `depth` hops.
95
+
96
+ Score = closeness (closer hops rank higher) + seed-name overlap.
97
+ """
98
+ if not self._adj:
99
+ return RetrievalResult(query=query, documents=[], score=0.0,
100
+ strategy=self.strategy)
101
+
102
+ q_tokens = set(_tokens(query))
103
+ seeds: list[str] = []
104
+ for node in self._adj:
105
+ if any(t in node.lower() for t in q_tokens):
106
+ seeds.append(node)
107
+ if not seeds:
108
+ # No direct hit — fall back to seeding from every node, capped.
109
+ # Lets the graph still surface SOMETHING for ambient queries.
110
+ seeds = list(self._adj.keys())[:3]
111
+
112
+ scored: dict[str, float] = {}
113
+ for seed in seeds:
114
+ scored.setdefault(seed, max(scored.get(seed, 0.0), 1.0))
115
+ # BFS, score = 1 / (1 + hops)
116
+ seen: set[str] = {seed}
117
+ q: deque[tuple[str, int]] = deque([(seed, 0)])
118
+ while q:
119
+ cur, d = q.popleft()
120
+ if d == depth:
121
+ continue
122
+ for nbr, _etype in self._adj[cur]:
123
+ if nbr in seen:
124
+ continue
125
+ seen.add(nbr)
126
+ s = 1.0 / (1.0 + d + 1)
127
+ scored[nbr] = max(scored.get(nbr, 0.0), s)
128
+ q.append((nbr, d + 1))
129
+
130
+ ranked = sorted(scored.items(), key=lambda p: p[1], reverse=True)[:k]
131
+ docs: list[Document] = []
132
+ for node, s in ranked:
133
+ text = self._node_text.get(node, node)
134
+ meta = dict(self._node_meta.get(node, {}))
135
+ meta["score"] = s
136
+ meta["edges"] = sorted(
137
+ (nbr, etype) for nbr, etype in self._adj[node]
138
+ )
139
+ docs.append(Document(id=node, text=text, metadata=meta))
140
+ agg = sum(s for _, s in ranked) / len(ranked) if ranked else 0.0
141
+ return RetrievalResult(query=query, documents=docs, score=agg,
142
+ strategy=self.strategy)
143
+
144
+ # ----- persistence -----
145
+
146
+ def _save(self) -> None:
147
+ assert self.json_path is not None
148
+ Path(self.json_path).parent.mkdir(parents=True, exist_ok=True)
149
+ # Sets aren't JSON-serialisable — flatten to lists.
150
+ data = {
151
+ "adj": {
152
+ k: sorted([list(t) for t in v]) for k, v in self._adj.items()
153
+ },
154
+ "node_text": self._node_text,
155
+ "node_meta": self._node_meta,
156
+ }
157
+ Path(self.json_path).write_text(json.dumps(data, indent=2))
158
+
159
+ def _load(self) -> None:
160
+ assert self.json_path is not None
161
+ data = json.loads(Path(self.json_path).read_text())
162
+ self._adj = defaultdict(set, {
163
+ k: {tuple(t) for t in v} for k, v in data.get("adj", {}).items()
164
+ })
165
+ self._node_text = data.get("node_text", {})
166
+ self._node_meta = data.get("node_meta", {})
167
+
168
+ def nodes(self) -> Iterable[str]:
169
+ return self._adj.keys()
@@ -0,0 +1,205 @@
1
+ """Hybrid retriever — sparse FTS5 (BM25) blended with dense cosine.
2
+
3
+ SQLite FTS5 gives a real BM25 score via its `bm25()` ranking function.
4
+ For the dense leg, we use a *hashing trick* — every token is hashed into one
5
+ of `dim` buckets, weighted by sublinear TF, then ℓ2-normalised. Cosine
6
+ similarity is the dot product of two normalised vectors. Pure stdlib.
7
+
8
+ The combined score is `alpha * dense + (1 - alpha) * sparse`, both legs
9
+ normalised to [0, 1] across the candidate pool.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import hashlib
14
+ import json
15
+ import math
16
+ import re
17
+ import sqlite3
18
+ from collections import Counter
19
+ from pathlib import Path
20
+
21
+ from omega_engine.rag.base import Document, RetrievalResult
22
+
23
+
24
+ _TOKEN_RE = re.compile(r"[A-Za-z0-9]+")
25
+
26
+
27
+ def _tokens(text: str) -> list[str]:
28
+ return [t.lower() for t in _TOKEN_RE.findall(text)]
29
+
30
+
31
+ def _hash_to_bucket(token: str, dim: int) -> int:
32
+ # md5 is fast and stable — we only need a uniform-ish bucket index, not
33
+ # cryptographic security.
34
+ h = hashlib.md5(token.encode("utf-8")).digest()
35
+ return int.from_bytes(h[:4], "big") % dim
36
+
37
+
38
+ def _vectorise(text: str, dim: int) -> list[float]:
39
+ """Hashed-feature vector with sublinear TF, ℓ2-normalised."""
40
+ counts: Counter[int] = Counter()
41
+ for tok in _tokens(text):
42
+ counts[_hash_to_bucket(tok, dim)] += 1
43
+ vec = [0.0] * dim
44
+ for bucket, c in counts.items():
45
+ # 1 + log(tf) damps very common tokens — the classic tf-idf weighting.
46
+ vec[bucket] = 1.0 + math.log(c)
47
+ norm = math.sqrt(sum(v * v for v in vec))
48
+ if norm == 0.0:
49
+ return vec
50
+ return [v / norm for v in vec]
51
+
52
+
53
+ def _cosine(a: list[float], b: list[float]) -> float:
54
+ # Both vectors are already ℓ2-normalised → cosine == dot product.
55
+ return sum(x * y for x, y in zip(a, b))
56
+
57
+
58
+ def _normalise(values: list[float]) -> list[float]:
59
+ """Min-max scale a list into [0, 1]. Empty / flat → all zeros."""
60
+ if not values:
61
+ return values
62
+ lo, hi = min(values), max(values)
63
+ if hi - lo < 1e-12:
64
+ return [0.0 for _ in values]
65
+ return [(v - lo) / (hi - lo) for v in values]
66
+
67
+
68
+ _SCHEMA = """
69
+ CREATE VIRTUAL TABLE IF NOT EXISTS docs_fts USING fts5(
70
+ id UNINDEXED, text, tokenize = 'unicode61'
71
+ );
72
+ CREATE TABLE IF NOT EXISTS docs_meta (
73
+ id TEXT PRIMARY KEY,
74
+ text TEXT NOT NULL,
75
+ meta TEXT NOT NULL DEFAULT '{}',
76
+ vec TEXT NOT NULL
77
+ );
78
+ """
79
+
80
+
81
+ class HybridRetriever:
82
+ """Sparse FTS5 + dense hashed-cosine, combined per `alpha`.
83
+
84
+ `alpha = 1` → pure dense. `alpha = 0` → pure sparse. Default 0.5 blends.
85
+ """
86
+
87
+ strategy = "hybrid"
88
+
89
+ def __init__(
90
+ self,
91
+ db_path: str | Path,
92
+ *,
93
+ dim: int = 256,
94
+ alpha: float = 0.5,
95
+ ) -> None:
96
+ self.db_path = str(db_path)
97
+ self.dim = dim
98
+ self.alpha = alpha
99
+ Path(self.db_path).parent.mkdir(parents=True, exist_ok=True)
100
+ self._conn = sqlite3.connect(self.db_path, isolation_level=None)
101
+ self._conn.row_factory = sqlite3.Row
102
+ self._conn.execute("PRAGMA journal_mode=WAL;")
103
+ self._conn.execute("PRAGMA synchronous=NORMAL;")
104
+ self._conn.executescript(_SCHEMA)
105
+
106
+ # ----- ingest -----
107
+
108
+ def index(self, documents: list[Document]) -> int:
109
+ """Index a batch. Returns the number of docs written. Idempotent on id."""
110
+ n = 0
111
+ with self._conn:
112
+ for d in documents:
113
+ vec = _vectorise(d.text, self.dim)
114
+ self._conn.execute(
115
+ "INSERT OR REPLACE INTO docs_meta (id, text, meta, vec) "
116
+ "VALUES (?, ?, ?, ?)",
117
+ (d.id, d.text, json.dumps(d.metadata), json.dumps(vec)),
118
+ )
119
+ # FTS5 has no native upsert — delete-then-insert is the idiom.
120
+ self._conn.execute("DELETE FROM docs_fts WHERE id = ?", (d.id,))
121
+ self._conn.execute(
122
+ "INSERT INTO docs_fts (id, text) VALUES (?, ?)", (d.id, d.text)
123
+ )
124
+ n += 1
125
+ return n
126
+
127
+ def count(self) -> int:
128
+ cur = self._conn.execute("SELECT COUNT(*) AS c FROM docs_meta")
129
+ return int(cur.fetchone()["c"])
130
+
131
+ # ----- retrieval -----
132
+
133
+ def retrieve(self, query: str, k: int = 5) -> RetrievalResult:
134
+ if k <= 0 or self.count() == 0:
135
+ return RetrievalResult(query=query, documents=[], score=0.0,
136
+ strategy=self.strategy)
137
+
138
+ # --- sparse leg: FTS5 + bm25. bm25() returns a NEGATIVE score (lower
139
+ # is better), so we negate it before normalising.
140
+ sparse_rows: dict[str, float] = {}
141
+ fts_query = _fts5_safe(query)
142
+ if fts_query:
143
+ try:
144
+ cur = self._conn.execute(
145
+ "SELECT id, bm25(docs_fts) AS score FROM docs_fts "
146
+ "WHERE docs_fts MATCH ? ORDER BY score LIMIT ?",
147
+ (fts_query, k * 4),
148
+ )
149
+ for row in cur.fetchall():
150
+ sparse_rows[row["id"]] = -float(row["score"])
151
+ except sqlite3.OperationalError:
152
+ # malformed FTS5 query — fall back to dense-only
153
+ sparse_rows = {}
154
+
155
+ # --- dense leg: cosine over every indexed doc (small corpora; for
156
+ # larger corpora a clustered ANN goes here, contract identical).
157
+ qvec = _vectorise(query, self.dim)
158
+ dense_rows: dict[str, float] = {}
159
+ cur = self._conn.execute("SELECT id, vec FROM docs_meta")
160
+ for row in cur.fetchall():
161
+ v = json.loads(row["vec"])
162
+ dense_rows[row["id"]] = _cosine(qvec, v)
163
+
164
+ # --- combine: union of candidates, min-max each leg, alpha blend.
165
+ candidates = set(sparse_rows) | set(dense_rows)
166
+ if not candidates:
167
+ return RetrievalResult(query=query, documents=[], score=0.0,
168
+ strategy=self.strategy)
169
+
170
+ ids = list(candidates)
171
+ sparse_vec = [sparse_rows.get(i, 0.0) for i in ids]
172
+ dense_vec = [dense_rows.get(i, 0.0) for i in ids]
173
+ sparse_n = _normalise(sparse_vec)
174
+ dense_n = _normalise(dense_vec)
175
+ combined = [
176
+ (self.alpha * d) + ((1 - self.alpha) * s)
177
+ for d, s in zip(dense_n, sparse_n)
178
+ ]
179
+
180
+ ranked = sorted(zip(ids, combined), key=lambda p: p[1], reverse=True)[:k]
181
+ docs: list[Document] = []
182
+ for doc_id, score in ranked:
183
+ cur = self._conn.execute(
184
+ "SELECT text, meta FROM docs_meta WHERE id = ?", (doc_id,)
185
+ )
186
+ row = cur.fetchone()
187
+ if not row:
188
+ continue
189
+ meta = json.loads(row["meta"])
190
+ meta["score"] = score
191
+ docs.append(Document(id=doc_id, text=row["text"], metadata=meta))
192
+
193
+ agg = sum(s for _, s in ranked) / len(ranked) if ranked else 0.0
194
+ return RetrievalResult(query=query, documents=docs, score=agg,
195
+ strategy=self.strategy)
196
+
197
+ def close(self) -> None:
198
+ self._conn.close()
199
+
200
+
201
+ def _fts5_safe(query: str) -> str:
202
+ """Coerce a freeform query into something FTS5 can parse — strip syntax
203
+ chars, OR the surviving tokens together. Returns "" if nothing remains."""
204
+ toks = _tokens(query)
205
+ return " OR ".join(toks) if toks else ""
@@ -0,0 +1,136 @@
1
+ """Multimodal retriever — PDFs and images on top of a text retriever.
2
+
3
+ v1 keeps the surface honest:
4
+ * PDFs are converted to text via `pdftotext` if the binary is on PATH,
5
+ otherwise the doc is registered with its path + an empty body (no fake
6
+ text, no hallucinated extraction).
7
+ * Images get a caption from the provider (role "rag-caption") and are
8
+ indexed by that caption + their path. If the provider returns nothing,
9
+ the image still indexes by filename.
10
+
11
+ The underlying text index is any text-mode Retriever (typically
12
+ HybridRetriever) — so a query "the architecture diagram explaining the
13
+ event log" can surface an image whose caption matches.
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import shutil
18
+ import subprocess
19
+ from pathlib import Path
20
+
21
+ from omega_engine.provider import AgentProvider, AgentRequest
22
+ from omega_engine.rag.base import Document, RetrievalResult, Retriever
23
+
24
+
25
+ def _pdftotext_available() -> bool:
26
+ return shutil.which("pdftotext") is not None
27
+
28
+
29
+ def _extract_pdf_text(path: Path) -> str:
30
+ """Best-effort PDF → text. Returns "" when pdftotext is missing or fails.
31
+ NEVER fakes output (Karpathy: think before coding — no hallucination)."""
32
+ if not _pdftotext_available():
33
+ return ""
34
+ try:
35
+ out = subprocess.run(
36
+ ["pdftotext", "-q", str(path), "-"],
37
+ capture_output=True, text=True, timeout=15, check=False,
38
+ )
39
+ return out.stdout if out.returncode == 0 else ""
40
+ except (subprocess.TimeoutExpired, OSError):
41
+ return ""
42
+
43
+
44
+ class MultimodalRetriever:
45
+ """Wraps a text retriever; understands `add_pdf` and `add_image`."""
46
+
47
+ strategy = "multimodal"
48
+
49
+ # `Retriever` (Protocol) needs an `index` method when we use HybridRetriever.
50
+ # We type-hint loosely so any object with `retrieve` works AND any
51
+ # object that *also* has `index` accepts new docs.
52
+ def __init__(
53
+ self,
54
+ inner: Retriever,
55
+ provider: AgentProvider | None = None,
56
+ ) -> None:
57
+ self.inner = inner
58
+ self.provider = provider
59
+ self._registered: dict[str, dict] = {} # id → {kind, path, caption}
60
+
61
+ # ----- ingest -----
62
+
63
+ def add_pdf(self, doc_id: str, path: str | Path) -> Document:
64
+ """Extract text via pdftotext if available; index whatever survives."""
65
+ p = Path(path)
66
+ text = _extract_pdf_text(p)
67
+ meta = {
68
+ "modality": "pdf",
69
+ "source": str(p),
70
+ "extracted": bool(text),
71
+ }
72
+ doc = Document(id=doc_id, text=text or f"[pdf:{p.name}]", metadata=meta)
73
+ self._register(doc)
74
+ return doc
75
+
76
+ def add_image(
77
+ self,
78
+ doc_id: str,
79
+ path: str | Path,
80
+ *,
81
+ caption: str | None = None,
82
+ ) -> Document:
83
+ """Index an image by its caption. Caption is provider-generated
84
+ unless one is passed in. With no provider and no caption, we fall
85
+ back to the filename so the image is still discoverable."""
86
+ p = Path(path)
87
+ final_caption = caption
88
+ if final_caption is None and self.provider is not None:
89
+ result = self.provider.run(AgentRequest(
90
+ role="rag-caption",
91
+ prompt=f"Caption the image at {p}",
92
+ context={"path": str(p)},
93
+ ))
94
+ final_caption = (result.artifacts or {}).get("caption")
95
+ if not final_caption:
96
+ final_caption = p.stem.replace("_", " ").replace("-", " ")
97
+ meta = {
98
+ "modality": "image",
99
+ "source": str(p),
100
+ "caption": final_caption,
101
+ }
102
+ doc = Document(id=doc_id, text=final_caption, metadata=meta)
103
+ self._register(doc)
104
+ return doc
105
+
106
+ def add_text(self, doc_id: str, text: str, **meta) -> Document:
107
+ """Plain text passthrough — keeps the retriever uniformly usable."""
108
+ m = {"modality": "text", **meta}
109
+ doc = Document(id=doc_id, text=text, metadata=m)
110
+ self._register(doc)
111
+ return doc
112
+
113
+ def _register(self, doc: Document) -> None:
114
+ self._registered[doc.id] = doc.metadata
115
+ index = getattr(self.inner, "index", None)
116
+ if callable(index):
117
+ index([doc])
118
+ # If the inner retriever has no `index`, the caller is responsible
119
+ # for populating it elsewhere — we still track the modality metadata.
120
+
121
+ # ----- retrieval -----
122
+
123
+ def retrieve(self, query: str, k: int = 5) -> RetrievalResult:
124
+ result = self.inner.retrieve(query, k=k)
125
+ # Inject modality metadata for any doc we registered.
126
+ for d in result.documents:
127
+ if d.id in self._registered:
128
+ d.metadata.setdefault(
129
+ "modality", self._registered[d.id].get("modality", "text"),
130
+ )
131
+ return RetrievalResult(
132
+ query=query,
133
+ documents=result.documents,
134
+ score=result.score,
135
+ strategy=self.strategy,
136
+ )
@@ -0,0 +1,110 @@
1
+ """RAGRouter — classifies a query and picks the right inner strategy, then
2
+ wraps the result in the Corrective envelope.
3
+
4
+ Routing happens in two steps:
5
+ 1. A cheap heuristic ("does the query look relational? mention an image
6
+ or PDF? have a 'why/how' shape?") gives a default.
7
+ 2. The provider (role "rag-route") gets a chance to override; its choice
8
+ wins when it picks one of the registered strategies.
9
+
10
+ The Corrective envelope wraps every dispatch — that's the project's stance:
11
+ "check / recheck until 100%" applied to retrieval (ARCHITECTURE.md §7).
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import re
16
+ from typing import Iterable
17
+
18
+ from omega_engine.provider import AgentProvider, AgentRequest
19
+ from omega_engine.rag.base import RetrievalResult, Retriever
20
+ from omega_engine.rag.corrective import CorrectiveRetriever
21
+
22
+
23
+ _GRAPH_HINTS = re.compile(
24
+ r"\b(depend|related|connection|who|graph|owner|"
25
+ r"between|link|relation|adjacent|connected)\b",
26
+ re.IGNORECASE,
27
+ )
28
+ _MULTIMODAL_HINTS = re.compile(
29
+ r"\b(image|picture|screenshot|diagram|pdf|figure|chart|photo)\b",
30
+ re.IGNORECASE,
31
+ )
32
+ _AGENTIC_HINTS = re.compile(
33
+ r"\b(why|how|explain|compare|trace|step by step|deep dive)\b",
34
+ re.IGNORECASE,
35
+ )
36
+
37
+
38
+ class RAGRouter:
39
+ """Routes a query to one of the registered strategies, then wraps in CRAG."""
40
+
41
+ def __init__(
42
+ self,
43
+ strategies: dict[str, Retriever],
44
+ provider: AgentProvider,
45
+ *,
46
+ default: str = "hybrid",
47
+ corrective: bool = True,
48
+ threshold: float = 70.0,
49
+ max_retries: int = 2,
50
+ ) -> None:
51
+ if not strategies:
52
+ raise ValueError("RAGRouter needs at least one strategy")
53
+ self.strategies = dict(strategies)
54
+ self.provider = provider
55
+ self.default = default if default in self.strategies else next(iter(self.strategies))
56
+ self.corrective = corrective
57
+ self.threshold = threshold
58
+ self.max_retries = max_retries
59
+
60
+ def classify(self, query: str) -> str:
61
+ """Pick a strategy name. Heuristic first, provider may override."""
62
+ # 1. Cheap heuristic — works with no provider.
63
+ heuristic = self.default
64
+ if "multimodal" in self.strategies and _MULTIMODAL_HINTS.search(query):
65
+ heuristic = "multimodal"
66
+ elif "graph" in self.strategies and _GRAPH_HINTS.search(query):
67
+ heuristic = "graph"
68
+ elif "agentic" in self.strategies and _AGENTIC_HINTS.search(query):
69
+ heuristic = "agentic"
70
+
71
+ # 2. Provider override. If it returns a non-registered strategy, we
72
+ # ignore it (never trust a free-form provider blindly).
73
+ try:
74
+ result = self.provider.run(AgentRequest(
75
+ role="rag-route",
76
+ prompt=f"Classify retrieval strategy for: {query}",
77
+ context={
78
+ "query": query,
79
+ "available": sorted(self.strategies.keys()),
80
+ "heuristic": heuristic,
81
+ },
82
+ ))
83
+ chosen = (result.artifacts or {}).get("strategy")
84
+ if isinstance(chosen, str) and chosen in self.strategies:
85
+ return chosen
86
+ except Exception:
87
+ # Provider misbehaved — keep the heuristic, never crash retrieval.
88
+ pass
89
+ return heuristic
90
+
91
+ def retrieve(self, query: str, k: int = 5) -> RetrievalResult:
92
+ name = self.classify(query)
93
+ inner = self.strategies[name]
94
+ if self.corrective:
95
+ wrapped = CorrectiveRetriever(
96
+ inner,
97
+ self.provider,
98
+ threshold=self.threshold,
99
+ max_retries=self.max_retries,
100
+ )
101
+ result = wrapped.retrieve(query, k=k)
102
+ # Surface the chosen inner strategy in the result for observability.
103
+ result.strategy = f"router({name})->{result.strategy}"
104
+ return result
105
+ result = inner.retrieve(query, k=k)
106
+ result.strategy = f"router({name})->{result.strategy}"
107
+ return result
108
+
109
+ def names(self) -> Iterable[str]:
110
+ return self.strategies.keys()
@@ -63,14 +63,32 @@ def reduce(state: Optional[TaskState], event: Event) -> TaskState:
63
63
  return _TRANSITIONS[key]
64
64
 
65
65
 
66
- def reduce_task(events: Iterable[Event]) -> TaskState:
66
+ def reduce_task(events: Iterable[Event],
67
+ initial: Optional[TaskState] = None) -> TaskState:
67
68
  """Fold an ordered event stream into the current task state.
68
69
 
69
- The events MUST be ordered (the Event Store returns them by `ts, id`).
70
+ The events MUST be ordered (the Event Store returns them by rowid).
71
+ `initial` lets a snapshot-aware caller start the fold from a known state
72
+ (`store.events_since_snapshot` + `snap.state`) instead of from genesis.
70
73
  """
71
- state: Optional[TaskState] = None
74
+ state: Optional[TaskState] = initial
72
75
  for ev in events:
73
76
  state = reduce(state, ev)
74
77
  if state is None:
75
78
  raise IllegalTransition("empty event stream — task never created")
76
79
  return state
80
+
81
+
82
+ def reduce_task_fast(store, task_id: str) -> TaskState:
83
+ """Reduce a task using its latest snapshot if available, else full replay.
84
+
85
+ Bounded reduction time on a long event log. Correctness is identical to
86
+ `reduce_task(store.events_for(task_id))`.
87
+ """
88
+ snap = store.latest_snapshot(task_id)
89
+ if snap is None:
90
+ return reduce_task(store.events_for(task_id))
91
+ events_after = store.events_since_snapshot(task_id)
92
+ if not events_after:
93
+ return snap["state"]
94
+ return reduce_task(events_after, initial=snap["state"])
@@ -32,3 +32,31 @@ class ModelRouter:
32
32
  def single(cls, provider: AgentProvider) -> "ModelRouter":
33
33
  """A router that sends every role to one provider — used for tests."""
34
34
  return cls({provider.id: provider}, {}, provider.id)
35
+
36
+ @classmethod
37
+ def auto(cls) -> "ModelRouter":
38
+ """Build the best router for the host.
39
+
40
+ Preference order:
41
+
42
+ 1. ``claude`` CLI on PATH + logged in → ClaudeMaxProvider
43
+ (Max subscription, no API key).
44
+ 2. ``ANTHROPIC_API_KEY`` env var set → ClaudeProvider (API).
45
+ 3. Otherwise → MockProvider (deterministic offline).
46
+
47
+ Use this everywhere the engine needs a "sensible default" — the
48
+ mission runner, smoke, pursue, audit pipeline. Tests still use
49
+ ``single(MockProvider())`` for determinism.
50
+ """
51
+ import os
52
+ from omega_engine.provider import (
53
+ ClaudeMaxProvider,
54
+ ClaudeProvider,
55
+ MockProvider,
56
+ )
57
+
58
+ if ClaudeMaxProvider.is_available():
59
+ return cls.single(ClaudeMaxProvider())
60
+ if os.environ.get("ANTHROPIC_API_KEY"):
61
+ return cls.single(ClaudeProvider())
62
+ return cls.single(MockProvider())