apsimo 1.3.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 (614) hide show
  1. apsimo/__init__.py +38 -0
  2. apsimo/__main__.py +6 -0
  3. apsimo/agent/__init__.py +6 -0
  4. apsimo/agent/client.py +276 -0
  5. apsimo/agent/models.py +46 -0
  6. apsimo/agents/__init__.py +20 -0
  7. apsimo/agents/models.py +264 -0
  8. apsimo/agents/store.py +861 -0
  9. apsimo/agents/websocket.py +522 -0
  10. apsimo/api/__init__.py +1 -0
  11. apsimo/api/auth_telemetry.py +287 -0
  12. apsimo/api/authority.py +1203 -0
  13. apsimo/api/contact_grants.py +347 -0
  14. apsimo/api/middleware.py +483 -0
  15. apsimo/api/routers/__init__.py +1 -0
  16. apsimo/api/routers/commitment_work.py +265 -0
  17. apsimo/api/routers/context_gate.py +123 -0
  18. apsimo/api/routers/executions.py +140 -0
  19. apsimo/api/routers/followup_plans.py +147 -0
  20. apsimo/api/routers/governed_actions.py +162 -0
  21. apsimo/api/routers/host.py +14473 -0
  22. apsimo/api/routers/initiative_work.py +115 -0
  23. apsimo/api/routers/mining.py +104 -0
  24. apsimo/api/routers/observations.py +110 -0
  25. apsimo/api/routers/social_state.py +225 -0
  26. apsimo/api/routers/task_queue.py +2715 -0
  27. apsimo/api/routers/temporal_followups.py +251 -0
  28. apsimo/api/routers/transport.py +110 -0
  29. apsimo/api/routers/transport_ingress_api.py +240 -0
  30. apsimo/api/schemas/__init__.py +1 -0
  31. apsimo/api/schemas/host.py +1949 -0
  32. apsimo/autonomy/cli.py +110 -0
  33. apsimo/autonomy/condition_worker.py +437 -0
  34. apsimo/autonomy/config.py +424 -0
  35. apsimo/autonomy/loop.py +4316 -0
  36. apsimo/autonomy/registry.py +339 -0
  37. apsimo/autonomy/scheduler.py +1822 -0
  38. apsimo/autonomy/synthesis.py +449 -0
  39. apsimo/backup.py +962 -0
  40. apsimo/beliefs/__init__.py +23 -0
  41. apsimo/beliefs/contradictions.py +109 -0
  42. apsimo/beliefs/decay.py +61 -0
  43. apsimo/beliefs/engine.py +479 -0
  44. apsimo/beliefs/models.py +67 -0
  45. apsimo/beliefs/promotion.py +41 -0
  46. apsimo/beliefs/resolve.py +58 -0
  47. apsimo/beliefs/source_claims.py +690 -0
  48. apsimo/beliefs/source_projection.py +883 -0
  49. apsimo/beliefs/source_time.py +208 -0
  50. apsimo/beliefs/store.py +133 -0
  51. apsimo/briefings/aggregators.py +824 -0
  52. apsimo/briefings/composer.py +420 -0
  53. apsimo/briefings/config.py +55 -0
  54. apsimo/briefings/delivery.py +439 -0
  55. apsimo/briefings/engagement.py +97 -0
  56. apsimo/briefings/engine.py +274 -0
  57. apsimo/briefings/enhancer.py +99 -0
  58. apsimo/briefings/models.py +183 -0
  59. apsimo/briefings/scheduler.py +382 -0
  60. apsimo/briefings/store.py +435 -0
  61. apsimo/chain/__init__.py +48 -0
  62. apsimo/chain/block.py +100 -0
  63. apsimo/chain/cli.py +704 -0
  64. apsimo/chain/genesis.py +443 -0
  65. apsimo/chain/identity.py +416 -0
  66. apsimo/chain/keys.py +1025 -0
  67. apsimo/chain/local_keys.py +187 -0
  68. apsimo/chain/manager.py +290 -0
  69. apsimo/chain/node.py +163 -0
  70. apsimo/chain/plugin_transactions.py +371 -0
  71. apsimo/chain/protocol.py +220 -0
  72. apsimo/chain/state_machine.py +676 -0
  73. apsimo/chain/storage.py +503 -0
  74. apsimo/chain/transactions.py +250 -0
  75. apsimo/chain/validation.py +397 -0
  76. apsimo/channels/__init__.py +1 -0
  77. apsimo/channels/manifest.py +31 -0
  78. apsimo/channels/migrations/001_channels_schema.sql +12 -0
  79. apsimo/channels/phone_gateways.py +42 -0
  80. apsimo/channels/presence.py +188 -0
  81. apsimo/channels/router.py +235 -0
  82. apsimo/channels/store.py +231 -0
  83. apsimo/cli.py +2688 -0
  84. apsimo/cognition/__init__.py +11 -0
  85. apsimo/cognition/charter.py +398 -0
  86. apsimo/cognition/drive_governance.py +3530 -0
  87. apsimo/cognition/evidence_pipeline.py +1627 -0
  88. apsimo/cognition/external_events.py +932 -0
  89. apsimo/cognition/goal_spine.py +3488 -0
  90. apsimo/cognition/introspection.py +214 -0
  91. apsimo/cognition/prompt.py +150 -0
  92. apsimo/cognition/runtime.py +108 -0
  93. apsimo/cognition/trigger.py +154 -0
  94. apsimo/commitments/__init__.py +18 -0
  95. apsimo/commitments/local_work.py +355 -0
  96. apsimo/commitments/store.py +1052 -0
  97. apsimo/commitments/work.py +91 -0
  98. apsimo/compat.py +53 -0
  99. apsimo/compression/__init__.py +467 -0
  100. apsimo/connectors/__init__.py +21 -0
  101. apsimo/connectors/base.py +152 -0
  102. apsimo/connectors/caldav_calendar.py +125 -0
  103. apsimo/connectors/fs_documents.py +85 -0
  104. apsimo/connectors/imap_email.py +138 -0
  105. apsimo/connectors/manager.py +218 -0
  106. apsimo/connectors/webhook_pull.py +88 -0
  107. apsimo/contacts/__init__.py +33 -0
  108. apsimo/contacts/comms.py +357 -0
  109. apsimo/contacts/config.py +79 -0
  110. apsimo/contacts/exporters/__init__.py +1 -0
  111. apsimo/contacts/exporters/vcard.py +71 -0
  112. apsimo/contacts/identity_links.py +251 -0
  113. apsimo/contacts/importer.py +280 -0
  114. apsimo/contacts/importers/__init__.py +1 -0
  115. apsimo/contacts/importers/batch.py +43 -0
  116. apsimo/contacts/importers/macos_contacts.py +101 -0
  117. apsimo/contacts/migrations/001_contacts_schema.sql +141 -0
  118. apsimo/contacts/migrations/002_trust_scopes.sql +36 -0
  119. apsimo/contacts/migrations/003_open_gateway_enum.sql +32 -0
  120. apsimo/contacts/migrations/004_contact_provision_operations.sql +18 -0
  121. apsimo/contacts/migrations/005_identity_links.sql +27 -0
  122. apsimo/contacts/models.py +308 -0
  123. apsimo/contacts/scoring.py +16 -0
  124. apsimo/contacts/store.py +1623 -0
  125. apsimo/contacts/transport_ingress.py +252 -0
  126. apsimo/contacts/world_bridge.py +314 -0
  127. apsimo/contextgate/__init__.py +69 -0
  128. apsimo/contextgate/chunker.py +169 -0
  129. apsimo/contextgate/estimate.py +54 -0
  130. apsimo/contextgate/gate.py +313 -0
  131. apsimo/contextgate/retrieve.py +115 -0
  132. apsimo/delivery/__init__.py +16 -0
  133. apsimo/delivery/bridge.py +1260 -0
  134. apsimo/delivery/channels.py +526 -0
  135. apsimo/delivery/classification.py +50 -0
  136. apsimo/delivery/rate_limiter.py +268 -0
  137. apsimo/delivery/reachout_policy.py +206 -0
  138. apsimo/directed/__init__.py +22 -0
  139. apsimo/directed/audit.py +167 -0
  140. apsimo/directed/intake.py +95 -0
  141. apsimo/directed/models.py +191 -0
  142. apsimo/directed/service.py +509 -0
  143. apsimo/directives/__init__.py +25 -0
  144. apsimo/directives/evidence.py +87 -0
  145. apsimo/directives/extractor.py +188 -0
  146. apsimo/directives/guard.py +364 -0
  147. apsimo/directives/models.py +206 -0
  148. apsimo/directives/service.py +372 -0
  149. apsimo/directives/store.py +167 -0
  150. apsimo/doctor.py +2173 -0
  151. apsimo/environment.py +43 -0
  152. apsimo/events/__init__.py +33 -0
  153. apsimo/events/broadcaster.py +98 -0
  154. apsimo/events/bus.py +217 -0
  155. apsimo/events/journal.py +863 -0
  156. apsimo/events/stream.py +131 -0
  157. apsimo/events/types.py +150 -0
  158. apsimo/execution_results.py +357 -0
  159. apsimo/feedback/__init__.py +5 -0
  160. apsimo/feedback/store.py +76 -0
  161. apsimo/feeds/__init__.py +19 -0
  162. apsimo/feeds/cli.py +84 -0
  163. apsimo/feeds/engine.py +437 -0
  164. apsimo/feeds/example-feed.yaml +77 -0
  165. apsimo/feeds/hermes_cron.py +126 -0
  166. apsimo/feeds/manager.py +235 -0
  167. apsimo/feeds/spec.py +250 -0
  168. apsimo/feeds/template.py +202 -0
  169. apsimo/gate/__init__.py +18 -0
  170. apsimo/gate/audit.py +61 -0
  171. apsimo/gate/communication_policy.py +166 -0
  172. apsimo/gate/config.py +72 -0
  173. apsimo/gate/context_provenance.py +170 -0
  174. apsimo/gate/env_risk.py +226 -0
  175. apsimo/gate/guard_audit.py +353 -0
  176. apsimo/gate/layers/__init__.py +1 -0
  177. apsimo/gate/layers/base.py +15 -0
  178. apsimo/gate/layers/l1_recipient.py +66 -0
  179. apsimo/gate/layers/l2_pii.py +134 -0
  180. apsimo/gate/layers/l3_cross_context.py +50 -0
  181. apsimo/gate/layers/l4_trust_tier.py +78 -0
  182. apsimo/gate/layers/l5_injection.py +199 -0
  183. apsimo/gate/layers/l6_review.py +86 -0
  184. apsimo/gate/layers/l7_delay.py +100 -0
  185. apsimo/gate/layers/tom2_epistemic.py +185 -0
  186. apsimo/gate/models.py +64 -0
  187. apsimo/gate/pending_dispatch.py +5 -0
  188. apsimo/gate/pipeline.py +206 -0
  189. apsimo/gate/rejection.py +259 -0
  190. apsimo/gate/response_guard.py +700 -0
  191. apsimo/gate/rulesets/injection_v1.yaml +51 -0
  192. apsimo/gate/surface_policy.py +189 -0
  193. apsimo/gate/taint.py +226 -0
  194. apsimo/genesis.json +9 -0
  195. apsimo/goals/__init__.py +100 -0
  196. apsimo/goals/config.py +38 -0
  197. apsimo/goals/decomposer.py +421 -0
  198. apsimo/goals/engine.py +617 -0
  199. apsimo/goals/inference.py +354 -0
  200. apsimo/goals/models.py +302 -0
  201. apsimo/goals/priority.py +270 -0
  202. apsimo/goals/queue_bridge.py +149 -0
  203. apsimo/goals/replan.py +450 -0
  204. apsimo/goals/schema.sql +89 -0
  205. apsimo/goals/store.py +692 -0
  206. apsimo/governed_actions.py +1708 -0
  207. apsimo/harness_integration/__init__.py +45 -0
  208. apsimo/harness_integration/context.py +41 -0
  209. apsimo/harness_integration/skills.py +231 -0
  210. apsimo/identity/__init__.py +26 -0
  211. apsimo/identity/participants.py +181 -0
  212. apsimo/identity/resolver.py +329 -0
  213. apsimo/identity_bootstrap/__init__.py +5 -0
  214. apsimo/identity_bootstrap/builder.py +208 -0
  215. apsimo/identity_bootstrap/corpus.py +443 -0
  216. apsimo/identity_bootstrap/models.py +54 -0
  217. apsimo/identity_bootstrap/runner.py +353 -0
  218. apsimo/identity_bootstrap/seeders/__init__.py +25 -0
  219. apsimo/identity_bootstrap/seeders/briefings.py +109 -0
  220. apsimo/identity_bootstrap/seeders/chain.py +57 -0
  221. apsimo/identity_bootstrap/seeders/goals.py +128 -0
  222. apsimo/identity_bootstrap/seeders/memory.py +191 -0
  223. apsimo/identity_bootstrap/seeders/neo4j_cognition.py +79 -0
  224. apsimo/identity_bootstrap/seeders/relationship.py +152 -0
  225. apsimo/identity_bootstrap/seeders/sessions.py +67 -0
  226. apsimo/identity_bootstrap/seeders/skills.py +92 -0
  227. apsimo/identity_bootstrap/seeders/task_queue.py +72 -0
  228. apsimo/identity_bootstrap/seeders/world_model.py +143 -0
  229. apsimo/identity_bootstrap/self_query.py +92 -0
  230. apsimo/identity_bootstrap/self_reflection.py +155 -0
  231. apsimo/identity_bootstrap/skill.py +37 -0
  232. apsimo/identity_bootstrap/verifier.py +436 -0
  233. apsimo/initiatives/__init__.py +20 -0
  234. apsimo/initiatives/action_registry.py +454 -0
  235. apsimo/initiatives/approval_authority.py +2105 -0
  236. apsimo/initiatives/approval_policy.py +123 -0
  237. apsimo/initiatives/assignment.py +263 -0
  238. apsimo/initiatives/backup_evidence.py +100 -0
  239. apsimo/initiatives/context_freshness.py +103 -0
  240. apsimo/initiatives/models.py +318 -0
  241. apsimo/initiatives/native_work.py +270 -0
  242. apsimo/initiatives/standing_approvals.py +232 -0
  243. apsimo/initiatives/store.py +1081 -0
  244. apsimo/initiatives/temporal_followup.py +410 -0
  245. apsimo/intelligence/__init__.py +1 -0
  246. apsimo/intelligence/cognition/__init__.py +24 -0
  247. apsimo/intelligence/cognition/gap_detector.py +148 -0
  248. apsimo/intelligence/cognition/metalearner.py +547 -0
  249. apsimo/intelligence/cognition/metrics_collector.py +217 -0
  250. apsimo/intelligence/cognition/performance_index.py +299 -0
  251. apsimo/intelligence/cognition/registry.py +192 -0
  252. apsimo/intelligence/cognition/strategy_adjuster.py +222 -0
  253. apsimo/intelligence/cognition/types.py +16 -0
  254. apsimo/intelligence/components/__init__.py +66 -0
  255. apsimo/intelligence/components/anomaly_detector.py +413 -0
  256. apsimo/intelligence/components/initiative_engine.py +2643 -0
  257. apsimo/intelligence/components/preference_learner.py +521 -0
  258. apsimo/intelligence/components/research_orchestrator.py +358 -0
  259. apsimo/intelligence/components/self_directed_thinker.py +221 -0
  260. apsimo/intelligence/components/self_reflector.py +252 -0
  261. apsimo/intelligence/components/session_continuity.py +154 -0
  262. apsimo/intelligence/components/task_planner.py +320 -0
  263. apsimo/intelligence/components/tool_learner.py +217 -0
  264. apsimo/intelligence/graph/__init__.py +79 -0
  265. apsimo/intelligence/graph/client.py +2483 -0
  266. apsimo/intelligence/graph/consolidator.py +405 -0
  267. apsimo/intelligence/graph/distiller.py +312 -0
  268. apsimo/intelligence/graph/migrations.py +129 -0
  269. apsimo/intelligence/graph/queries.py +248 -0
  270. apsimo/intelligence/graph/recall.py +281 -0
  271. apsimo/intelligence/graph/reconciler.py +144 -0
  272. apsimo/intelligence/graph/schema.py +337 -0
  273. apsimo/intelligence/graph/selection.py +252 -0
  274. apsimo/intelligence/learning/__init__.py +17 -0
  275. apsimo/intelligence/learning/continuous_learner.py +245 -0
  276. apsimo/intelligence/learning/feedback_store.py +321 -0
  277. apsimo/intelligence/mind_model/__init__.py +1 -0
  278. apsimo/intelligence/mind_model/graph_baseline.py +136 -0
  279. apsimo/intelligence/mind_model/signal_collector.py +361 -0
  280. apsimo/intelligence/relationships/__init__.py +11 -0
  281. apsimo/intelligence/relationships/profiler.py +389 -0
  282. apsimo/intelligence/relationships/scorer.py +560 -0
  283. apsimo/intelligence/relationships/signal_floor.py +66 -0
  284. apsimo/intelligence/relationships/trust_tiers.py +300 -0
  285. apsimo/intelligence/synthesis/__init__.py +40 -0
  286. apsimo/intelligence/synthesis/connection_discoverer.py +379 -0
  287. apsimo/intelligence/synthesis/cross_domain_analyzer.py +287 -0
  288. apsimo/intelligence/synthesis/insight_deliverer.py +171 -0
  289. apsimo/intelligence/synthesis/insight_store.py +79 -0
  290. apsimo/intelligence/synthesis/insight_validator.py +183 -0
  291. apsimo/intelligence/synthesis/novelty_scorer.py +267 -0
  292. apsimo/intelligence/turn_middleware/__init__.py +15 -0
  293. apsimo/intelligence/turn_middleware/memory_sync.py +119 -0
  294. apsimo/mcp/__init__.py +41 -0
  295. apsimo/mcp/__main__.py +6 -0
  296. apsimo/mcp/config.py +287 -0
  297. apsimo/mcp/server.py +501 -0
  298. apsimo/migrations.py +187 -0
  299. apsimo/mining/__init__.py +27 -0
  300. apsimo/mining/corpus.py +239 -0
  301. apsimo/mining/escalations.py +289 -0
  302. apsimo/mining/models.py +169 -0
  303. apsimo/mining/store.py +210 -0
  304. apsimo/models/__init__.py +30 -0
  305. apsimo/models/memory.py +80 -0
  306. apsimo/models/mesh.py +72 -0
  307. apsimo/models/person.py +104 -0
  308. apsimo/models/signal.py +108 -0
  309. apsimo/observations/__init__.py +15 -0
  310. apsimo/observations/store.py +277 -0
  311. apsimo/patterns/__init__.py +6 -0
  312. apsimo/patterns/extract.py +187 -0
  313. apsimo/patterns/store.py +227 -0
  314. apsimo/persona/__init__.py +1 -0
  315. apsimo/persona/engine.py +611 -0
  316. apsimo/persona/manifest.py +140 -0
  317. apsimo/projects/__init__.py +28 -0
  318. apsimo/projects/engine.py +1681 -0
  319. apsimo/projects/event_outbox.py +188 -0
  320. apsimo/projects/models.py +216 -0
  321. apsimo/projects/planner.py +181 -0
  322. apsimo/projects/store.py +1446 -0
  323. apsimo/proposals/__init__.py +12 -0
  324. apsimo/proposals/engine.py +114 -0
  325. apsimo/proposals/models.py +207 -0
  326. apsimo/qualification/__init__.py +1 -0
  327. apsimo/qualification/cases.py +75 -0
  328. apsimo/qualification/cli.py +51 -0
  329. apsimo/qualification/memory_cases.py +209 -0
  330. apsimo/qualification/records.py +92 -0
  331. apsimo/qualification/report.py +87 -0
  332. apsimo/qualification/runner.py +311 -0
  333. apsimo/qualification/structured_cases.py +131 -0
  334. apsimo/reasoning/__init__.py +13 -0
  335. apsimo/reasoning/executor.py +506 -0
  336. apsimo/reasoning/loop.py +373 -0
  337. apsimo/reasoning/native_tools/__init__.py +16 -0
  338. apsimo/reasoning/native_tools/calculate.py +141 -0
  339. apsimo/reasoning/native_tools/file_ops.py +150 -0
  340. apsimo/reasoning/native_tools/web_search.py +49 -0
  341. apsimo/reasoning/tool_policy.py +182 -0
  342. apsimo/redact/__init__.py +176 -0
  343. apsimo/repos/__init__.py +5 -0
  344. apsimo/repos/mirrors.py +204 -0
  345. apsimo/research/__init__.py +41 -0
  346. apsimo/research/artifact.py +482 -0
  347. apsimo/research/gatherer.py +387 -0
  348. apsimo/research/pipeline.py +513 -0
  349. apsimo/research/search/__init__.py +7 -0
  350. apsimo/research/search/base.py +41 -0
  351. apsimo/research/search/brave.py +59 -0
  352. apsimo/research/search/cache.py +51 -0
  353. apsimo/research/search/duckduckgo.py +103 -0
  354. apsimo/research/search/orchestrator.py +119 -0
  355. apsimo/research/search/serpapi.py +59 -0
  356. apsimo/research/search/tavily.py +59 -0
  357. apsimo/research/synthesizer.py +309 -0
  358. apsimo/router/__init__.py +30 -0
  359. apsimo/router/complexity_scorer.py +148 -0
  360. apsimo/router/endpoints.py +153 -0
  361. apsimo/router/fallback.py +58 -0
  362. apsimo/router/functions.py +243 -0
  363. apsimo/router/native_policy.py +52 -0
  364. apsimo/router/router.py +762 -0
  365. apsimo/router/self_learning.py +174 -0
  366. apsimo/router/tiers.py +677 -0
  367. apsimo/sandbox/__init__.py +21 -0
  368. apsimo/sandbox/backend.py +195 -0
  369. apsimo/sandbox/manager.py +173 -0
  370. apsimo/scope_bounds.py +7 -0
  371. apsimo/secrets/__init__.py +6 -0
  372. apsimo/secrets/backends/__init__.py +8 -0
  373. apsimo/secrets/backends/base.py +42 -0
  374. apsimo/secrets/backends/env.py +110 -0
  375. apsimo/secrets/backends/keyring.py +72 -0
  376. apsimo/secrets/backends/onepassword.py +232 -0
  377. apsimo/secrets/cli.py +191 -0
  378. apsimo/secrets/manager.py +160 -0
  379. apsimo/secrets/migration.py +101 -0
  380. apsimo/secrets/types.py +98 -0
  381. apsimo/seed.py +41 -0
  382. apsimo/self_model/__init__.py +37 -0
  383. apsimo/self_model/appraisals.py +673 -0
  384. apsimo/self_model/benchmark.py +1314 -0
  385. apsimo/self_model/brief.py +40 -0
  386. apsimo/self_model/event_concerns.py +1128 -0
  387. apsimo/self_model/execution_forecasts.py +353 -0
  388. apsimo/self_model/expectations.py +1595 -0
  389. apsimo/self_model/experiments.py +1150 -0
  390. apsimo/self_model/journal.py +148 -0
  391. apsimo/self_model/judgments.py +705 -0
  392. apsimo/self_model/native_outcomes.py +55 -0
  393. apsimo/self_model/params.py +220 -0
  394. apsimo/self_model/perspective.py +246 -0
  395. apsimo/self_model/reconcile.py +183 -0
  396. apsimo/self_model/reply_forecasts.py +381 -0
  397. apsimo/self_model/runtime_forecasts.py +296 -0
  398. apsimo/self_model/runtime_models.py +67 -0
  399. apsimo/self_model/settlement.py +207 -0
  400. apsimo/self_model/situation.py +1731 -0
  401. apsimo/self_model/store.py +883 -0
  402. apsimo/self_model/supervised.py +137 -0
  403. apsimo/self_model/thinker.py +99 -0
  404. apsimo/self_model/trust.py +388 -0
  405. apsimo/self_model/workspace.py +2388 -0
  406. apsimo/server.py +4197 -0
  407. apsimo/services/__init__.py +1 -0
  408. apsimo/services/agent_bridge.py +474 -0
  409. apsimo/services/initiative_executor.py +914 -0
  410. apsimo/services/instance.py +297 -0
  411. apsimo/sessions/__init__.py +22 -0
  412. apsimo/sessions/config.py +13 -0
  413. apsimo/sessions/context_loader.py +88 -0
  414. apsimo/sessions/federation_session.py +75 -0
  415. apsimo/sessions/isolated_session.py +98 -0
  416. apsimo/sessions/reports.py +84 -0
  417. apsimo/sessions/store.py +148 -0
  418. apsimo/setup.py +2818 -0
  419. apsimo/setup_hermes.py +879 -0
  420. apsimo/setup_local_work.py +218 -0
  421. apsimo/setup_native_goals.py +134 -0
  422. apsimo/setup_native_reviews.py +115 -0
  423. apsimo/skills/__init__.py +10 -0
  424. apsimo/skills/base.py +108 -0
  425. apsimo/skills/budget.py +28 -0
  426. apsimo/skills/executor.py +493 -0
  427. apsimo/skills/executors/__init__.py +1 -0
  428. apsimo/skills/executors/behavioral_correction.py +75 -0
  429. apsimo/skills/executors/capability_gap.py +38 -0
  430. apsimo/skills/executors/data_quality.py +163 -0
  431. apsimo/skills/executors/knowledge_acquisition.py +41 -0
  432. apsimo/skills/executors/operational_hygiene.py +185 -0
  433. apsimo/skills/executors/subsystem_health.py +169 -0
  434. apsimo/skills/hermes_export.py +431 -0
  435. apsimo/skills/index.py +123 -0
  436. apsimo/skills/learning/__init__.py +21 -0
  437. apsimo/skills/learning/novelty_detector.py +206 -0
  438. apsimo/skills/learning/pattern_extractor.py +199 -0
  439. apsimo/skills/learning/triggers.py +159 -0
  440. apsimo/skills/loader.py +246 -0
  441. apsimo/skills/migrations/002_progressive_loading.sql +6 -0
  442. apsimo/skills/migrations/backfill_triggers.py +20 -0
  443. apsimo/skills/models.py +202 -0
  444. apsimo/skills/packager.py +128 -0
  445. apsimo/skills/protocols.py +70 -0
  446. apsimo/skills/registry.py +191 -0
  447. apsimo/skills/runtime.py +58 -0
  448. apsimo/skills/sandbox_runner.py +229 -0
  449. apsimo/skills/scheduler.py +129 -0
  450. apsimo/skills/schema.py +79 -0
  451. apsimo/skills/security/__init__.py +12 -0
  452. apsimo/skills/security/guards.py +53 -0
  453. apsimo/skills/security/scanner.py +223 -0
  454. apsimo/skills_memory/__init__.py +26 -0
  455. apsimo/skills_memory/distill.py +159 -0
  456. apsimo/skills_memory/models.py +85 -0
  457. apsimo/skills_memory/retrieve.py +62 -0
  458. apsimo/skills_memory/store.py +172 -0
  459. apsimo/surprise/__init__.py +6 -0
  460. apsimo/surprise/accumulation.py +57 -0
  461. apsimo/surprise/scorer.py +102 -0
  462. apsimo/surprise/store.py +203 -0
  463. apsimo/task_queue/__init__.py +69 -0
  464. apsimo/task_queue/action_receipts.py +148 -0
  465. apsimo/task_queue/approval_relay_canary.py +108 -0
  466. apsimo/task_queue/config.py +85 -0
  467. apsimo/task_queue/contract.py +361 -0
  468. apsimo/task_queue/events.py +130 -0
  469. apsimo/task_queue/governor.py +1031 -0
  470. apsimo/task_queue/handlers/__init__.py +16 -0
  471. apsimo/task_queue/handlers/base.py +37 -0
  472. apsimo/task_queue/handlers/inference.py +640 -0
  473. apsimo/task_queue/handlers/monitoring.py +116 -0
  474. apsimo/task_queue/handlers/registry.py +75 -0
  475. apsimo/task_queue/handlers/subtask_handler.py +173 -0
  476. apsimo/task_queue/handlers/system_maintenance.py +147 -0
  477. apsimo/task_queue/mesh_integration.py +111 -0
  478. apsimo/task_queue/models.py +317 -0
  479. apsimo/task_queue/queue_manager.py +8286 -0
  480. apsimo/task_queue/routing.py +287 -0
  481. apsimo/task_queue/scheduler.py +252 -0
  482. apsimo/task_queue/schema.sql +197 -0
  483. apsimo/task_queue/work_control.py +342 -0
  484. apsimo/task_queue/worker.py +993 -0
  485. apsimo/telemetry.py +145 -0
  486. apsimo/tom/__init__.py +6 -0
  487. apsimo/tom/affect.py +387 -0
  488. apsimo/tom/approvals.py +171 -0
  489. apsimo/tom/arcs.py +896 -0
  490. apsimo/tom/asymmetry.py +131 -0
  491. apsimo/tom/eligibility.py +248 -0
  492. apsimo/tom/engagement.py +214 -0
  493. apsimo/tom/exposure.py +214 -0
  494. apsimo/tom/extractor.py +306 -0
  495. apsimo/tom/fact_adapters.py +144 -0
  496. apsimo/tom/facts.py +326 -0
  497. apsimo/tom/integration.py +592 -0
  498. apsimo/tom/leveled.py +118 -0
  499. apsimo/tom/levels.py +247 -0
  500. apsimo/tom/recipient_audit.py +995 -0
  501. apsimo/tom/recipient_simulator.py +593 -0
  502. apsimo/tom/source_lineage.py +93 -0
  503. apsimo/tom/tom2.py +277 -0
  504. apsimo/tom/visibility.py +559 -0
  505. apsimo/tom/visibility_store.py +414 -0
  506. apsimo/tools/__init__.py +0 -0
  507. apsimo/tools/definitions.py +740 -0
  508. apsimo/tools/handlers.py +943 -0
  509. apsimo/toolsmith/__init__.py +26 -0
  510. apsimo/toolsmith/authority.py +166 -0
  511. apsimo/toolsmith/engine.py +559 -0
  512. apsimo/toolsmith/integrity.py +100 -0
  513. apsimo/toolsmith/miner.py +145 -0
  514. apsimo/toolsmith/policy.py +110 -0
  515. apsimo/toolsmith/registry.py +635 -0
  516. apsimo/turns/__init__.py +17 -0
  517. apsimo/turns/audio.py +134 -0
  518. apsimo/turns/documents.py +235 -0
  519. apsimo/turns/executions.py +486 -0
  520. apsimo/turns/hermes_history.py +245 -0
  521. apsimo/turns/hermes_kanban.py +268 -0
  522. apsimo/turns/hermes_work.py +96 -0
  523. apsimo/turns/idempotency.py +752 -0
  524. apsimo/turns/local_work.py +115 -0
  525. apsimo/turns/media.py +581 -0
  526. apsimo/turns/reported_workers.py +196 -0
  527. apsimo/turns/source_annotations.py +283 -0
  528. apsimo/turns/source_attribution.py +154 -0
  529. apsimo/turns/source_read.py +351 -0
  530. apsimo/turns/source_vectors.py +263 -0
  531. apsimo/turns/video.py +210 -0
  532. apsimo/util/autonomy_preset.py +220 -0
  533. apsimo/util/instance.py +92 -0
  534. apsimo/util/model_output.py +25 -0
  535. apsimo/util/quiet_hours.py +27 -0
  536. apsimo/util/session_safety.py +37 -0
  537. apsimo/util/temporal.py +343 -0
  538. apsimo/vector/__init__.py +75 -0
  539. apsimo/vector/backfill.py +171 -0
  540. apsimo/vector/caption.py +114 -0
  541. apsimo/vector/collections.py +51 -0
  542. apsimo/vector/config.py +102 -0
  543. apsimo/vector/embedder.py +670 -0
  544. apsimo/vector/image_preprocess.py +406 -0
  545. apsimo/vector/image_store.py +296 -0
  546. apsimo/vector/indexes.py +162 -0
  547. apsimo/vector/migrate.py +334 -0
  548. apsimo/vector/multimodal_provider.py +417 -0
  549. apsimo/vector/multimodal_types.py +87 -0
  550. apsimo/vector/openai_provider.py +119 -0
  551. apsimo/vector/query.py +49 -0
  552. apsimo/vector/reranker.py +565 -0
  553. apsimo/vector/safety_image.py +159 -0
  554. apsimo/vector/scanner.py +197 -0
  555. apsimo/vector/setup.py +289 -0
  556. apsimo/vector/store.py +533 -0
  557. apsimo/vector/tiers.py +263 -0
  558. apsimo/work_orders.py +925 -0
  559. apsimo/workers/__init__.py +21 -0
  560. apsimo/workers/agent_bridge.py +640 -0
  561. apsimo/workers/colony_worker.py +382 -0
  562. apsimo/workers/queue_worker.py +441 -0
  563. apsimo/workers/skills_sync.py +152 -0
  564. apsimo/world_model/__init__.py +71 -0
  565. apsimo/world_model/causal_maintenance.py +131 -0
  566. apsimo/world_model/causal_policy.py +43 -0
  567. apsimo/world_model/causal_query.py +125 -0
  568. apsimo/world_model/confidence.py +54 -0
  569. apsimo/world_model/config.py +64 -0
  570. apsimo/world_model/constants.py +97 -0
  571. apsimo/world_model/entities.py +145 -0
  572. apsimo/world_model/expectation_resolvers.py +177 -0
  573. apsimo/world_model/extraction/__init__.py +7 -0
  574. apsimo/world_model/extraction/base.py +62 -0
  575. apsimo/world_model/extraction/conversation_extractor.py +262 -0
  576. apsimo/world_model/extraction/detector.py +74 -0
  577. apsimo/world_model/extraction/document_extractor.py +78 -0
  578. apsimo/world_model/extraction/formats/__init__.py +24 -0
  579. apsimo/world_model/extraction/formats/csv_fmt.py +68 -0
  580. apsimo/world_model/extraction/formats/html_fmt.py +72 -0
  581. apsimo/world_model/extraction/formats/json_fmt.py +68 -0
  582. apsimo/world_model/extraction/formats/pdf.py +43 -0
  583. apsimo/world_model/extraction/formats/text.py +27 -0
  584. apsimo/world_model/extraction/llm_extractor.py +164 -0
  585. apsimo/world_model/extraction/pipeline.py +73 -0
  586. apsimo/world_model/integrations/__init__.py +5 -0
  587. apsimo/world_model/integrations/mind_model_bridge.py +115 -0
  588. apsimo/world_model/integrations/social_intel_bridge.py +120 -0
  589. apsimo/world_model/jobs/__init__.py +4 -0
  590. apsimo/world_model/jobs/extraction_job.py +168 -0
  591. apsimo/world_model/llm_extract.py +572 -0
  592. apsimo/world_model/neo4j/__init__.py +5 -0
  593. apsimo/world_model/neo4j/backend.py +654 -0
  594. apsimo/world_model/observations.py +155 -0
  595. apsimo/world_model/populator.py +307 -0
  596. apsimo/world_model/postgres/__init__.py +1 -0
  597. apsimo/world_model/postgres/backend.py +683 -0
  598. apsimo/world_model/relationships.py +25 -0
  599. apsimo/world_model/resolution/__init__.py +13 -0
  600. apsimo/world_model/resolution/entity_resolver.py +232 -0
  601. apsimo/world_model/resolution/merge_audit.py +16 -0
  602. apsimo/world_model/resolution/merge_workflow.py +117 -0
  603. apsimo/world_model/source_reports.py +121 -0
  604. apsimo/world_model/sqlite/__init__.py +4 -0
  605. apsimo/world_model/sqlite/backend.py +855 -0
  606. apsimo/world_model/sqlite/schema.sql +132 -0
  607. apsimo/world_model/store.py +545 -0
  608. apsimo-1.3.0.dist-info/METADATA +78 -0
  609. apsimo-1.3.0.dist-info/RECORD +614 -0
  610. apsimo-1.3.0.dist-info/WHEEL +5 -0
  611. apsimo-1.3.0.dist-info/entry_points.txt +11 -0
  612. apsimo-1.3.0.dist-info/licenses/LICENSE +21 -0
  613. apsimo-1.3.0.dist-info/top_level.txt +2 -0
  614. colony_sidecar/__init__.py +4 -0
@@ -0,0 +1,312 @@
1
+ """MemoryDistiller — promote frequently-recalled episodic memories into semantic facts.
2
+
3
+ Gap A from the intelligence-systems-improvement spec. Runs as a weekly
4
+ background task in the autonomy loop (after consolidation and pruning).
5
+
6
+ Algorithm:
7
+ 1. Identify episodic memories with high recall frequency and sufficient strength
8
+ 2. Cluster by shared entity mentions (union-find on entity overlap)
9
+ 3. For qualifying clusters (3+ members), create a semantic summary memory
10
+ 4. Mark source memories as distilled (they continue to decay naturally)
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import logging
16
+ import os
17
+ import uuid
18
+ from collections import defaultdict
19
+ from dataclasses import dataclass, field
20
+ from typing import Any, Dict, List, Optional, Set
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ @dataclass
26
+ class DistillationResult:
27
+ """Outcome of one MemoryDistiller.run() call."""
28
+
29
+ clusters_found: int = 0
30
+ memories_promoted: int = 0
31
+ source_memories_marked: int = 0
32
+ errors: List[str] = field(default_factory=list)
33
+ duration_ms: float = 0.0
34
+
35
+
36
+ class MemoryDistiller:
37
+ """Promote frequently-recalled episodic memories into durable semantic facts.
38
+
39
+ Args:
40
+ graph_client: ColonyGraph instance (or compatible mock with execute())
41
+ metrics: Optional ColonyMetricsCollector for instrumentation
42
+ min_recalls: Minimum recall count for a memory to be a distillation
43
+ candidate (None = COLONY_DISTILL_MIN_RECALLS, default 3)
44
+ min_strength: Minimum strength for a candidate
45
+ (None = COLONY_DISTILL_MIN_STRENGTH, default 0.5)
46
+ min_age_days: Minimum age in days, only distill established memories
47
+ (None = COLONY_DISTILL_MIN_AGE_DAYS, default 7)
48
+ min_cluster_size: Minimum cluster size to trigger distillation
49
+ candidate_limit: Max candidates per run
50
+
51
+ The env knobs exist because the defaults assume memories survive long
52
+ enough to accumulate 3 recalls over 7 days — on a fast-decay graph that
53
+ can mean nothing ever qualifies. An explicit constructor argument always
54
+ wins over the environment.
55
+ """
56
+
57
+ def __init__(
58
+ self,
59
+ graph_client: Any,
60
+ metrics: Optional[Any] = None,
61
+ min_recalls: Optional[int] = None,
62
+ min_strength: Optional[float] = None,
63
+ min_age_days: Optional[int] = None,
64
+ min_cluster_size: int = 3,
65
+ candidate_limit: int = 200,
66
+ ) -> None:
67
+ self.graph = graph_client
68
+ self._metrics = metrics
69
+ self._min_recalls = (self._env_int("COLONY_DISTILL_MIN_RECALLS", 3)
70
+ if min_recalls is None else min_recalls)
71
+ self._min_strength = (self._env_float("COLONY_DISTILL_MIN_STRENGTH", 0.5)
72
+ if min_strength is None else min_strength)
73
+ self._min_age_days = (self._env_int("COLONY_DISTILL_MIN_AGE_DAYS", 7)
74
+ if min_age_days is None else min_age_days)
75
+ self._min_cluster_size = min_cluster_size
76
+ self._candidate_limit = candidate_limit
77
+
78
+ @staticmethod
79
+ def _env_int(name: str, default: int) -> int:
80
+ try:
81
+ return int(os.environ.get(name, str(default)))
82
+ except (TypeError, ValueError):
83
+ return default
84
+
85
+ @staticmethod
86
+ def _env_float(name: str, default: float) -> float:
87
+ try:
88
+ return float(os.environ.get(name, str(default)))
89
+ except (TypeError, ValueError):
90
+ return default
91
+
92
+ async def run(self) -> DistillationResult:
93
+ """Execute one distillation pass. Never raises — errors are captured."""
94
+ import time
95
+ start = time.monotonic()
96
+ result = DistillationResult()
97
+
98
+ try:
99
+ candidates = await self._fetch_candidates()
100
+ except Exception as exc:
101
+ result.errors.append(f"fetch_candidates: {exc}")
102
+ result.duration_ms = (time.monotonic() - start) * 1000
103
+ return result
104
+
105
+ if not candidates:
106
+ result.duration_ms = (time.monotonic() - start) * 1000
107
+ return result
108
+
109
+ # Cluster by shared entities
110
+ clusters = self._cluster_by_entities(candidates)
111
+ result.clusters_found = len(clusters)
112
+
113
+ # Distill each qualifying cluster
114
+ for cluster in clusters:
115
+ try:
116
+ promoted = await self._distill_cluster(cluster)
117
+ if promoted:
118
+ result.memories_promoted += 1
119
+ result.source_memories_marked += len(cluster)
120
+ except Exception as exc:
121
+ result.errors.append(f"distill_cluster: {exc}")
122
+
123
+ result.duration_ms = (time.monotonic() - start) * 1000
124
+
125
+ if self._metrics is not None:
126
+ try:
127
+ self._metrics.record_distillation_run(
128
+ clusters=result.clusters_found,
129
+ promoted=result.memories_promoted,
130
+ )
131
+ except Exception:
132
+ pass
133
+
134
+ logger.info(
135
+ "MemoryDistiller: clusters=%d promoted=%d marked=%d errors=%d (%.1fms)",
136
+ result.clusters_found,
137
+ result.memories_promoted,
138
+ result.source_memories_marked,
139
+ len(result.errors),
140
+ result.duration_ms,
141
+ )
142
+ return result
143
+
144
+ async def _fetch_candidates(self) -> List[Dict[str, Any]]:
145
+ """Fetch episodic memories eligible for distillation."""
146
+ query = (
147
+ "MATCH (m:Memory) "
148
+ "WHERE m.type = 'episodic' "
149
+ " AND m.recalls >= $min_recalls "
150
+ " AND m.strength >= $min_strength "
151
+ " AND m.created_at < datetime() - duration({days: $min_age_days}) "
152
+ " AND coalesce(m.distilled, false) = false "
153
+ "OPTIONAL MATCH (m)-[:MENTIONS]->(e:Entity) "
154
+ "RETURN m.id AS id, m.content AS content, m.strength AS strength, "
155
+ " m.recalls AS recalls, collect(e.name) AS entities "
156
+ "ORDER BY m.recalls DESC "
157
+ "LIMIT $limit"
158
+ )
159
+ rows = await self._execute(
160
+ query,
161
+ min_recalls=self._min_recalls,
162
+ min_strength=self._min_strength,
163
+ min_age_days=self._min_age_days,
164
+ limit=self._candidate_limit,
165
+ )
166
+ return rows if rows else []
167
+
168
+ def _cluster_by_entities(
169
+ self, candidates: List[Dict[str, Any]]
170
+ ) -> List[List[Dict[str, Any]]]:
171
+ """Group memories that share 2+ entity mentions using union-find."""
172
+ # Build entity → memory indices mapping
173
+ entity_to_indices: Dict[str, List[int]] = defaultdict(list)
174
+ for idx, mem in enumerate(candidates):
175
+ for entity in (mem.get("entities") or []):
176
+ entity_to_indices[entity].append(idx)
177
+
178
+ # Union-find
179
+ parent: List[int] = list(range(len(candidates)))
180
+
181
+ def find(x: int) -> int:
182
+ while parent[x] != x:
183
+ parent[x] = parent[parent[x]]
184
+ x = parent[x]
185
+ return x
186
+
187
+ def union(a: int, b: int) -> None:
188
+ ra, rb = find(a), find(b)
189
+ if ra != rb:
190
+ parent[ra] = rb
191
+
192
+ # Union memories that share entities
193
+ for indices in entity_to_indices.values():
194
+ for i in range(1, len(indices)):
195
+ union(indices[0], indices[i])
196
+
197
+ # Group by root and filter for shared-entity overlap >= 2
198
+ groups: Dict[int, List[int]] = defaultdict(list)
199
+ for idx in range(len(candidates)):
200
+ groups[find(idx)].append(idx)
201
+
202
+ clusters: List[List[Dict[str, Any]]] = []
203
+ for member_indices in groups.values():
204
+ if len(member_indices) < self._min_cluster_size:
205
+ continue
206
+ cluster = [candidates[i] for i in member_indices]
207
+ # Verify the cluster actually shares entities (not just single-entity links)
208
+ all_entities: List[Set[str]] = [
209
+ set(m.get("entities") or []) for m in cluster
210
+ ]
211
+ if all_entities:
212
+ shared = all_entities[0]
213
+ for eset in all_entities[1:]:
214
+ shared = shared & eset
215
+ # At least some pair must share 2+ entities
216
+ if not shared:
217
+ # Check pairwise: any pair with 2+ shared?
218
+ has_overlap = False
219
+ for i in range(len(all_entities)):
220
+ for j in range(i + 1, len(all_entities)):
221
+ if len(all_entities[i] & all_entities[j]) >= 2:
222
+ has_overlap = True
223
+ break
224
+ if has_overlap:
225
+ break
226
+ if not has_overlap:
227
+ continue
228
+ clusters.append(cluster)
229
+
230
+ return clusters
231
+
232
+ async def _distill_cluster(self, cluster: List[Dict[str, Any]]) -> bool:
233
+ """Create a semantic memory from a cluster of episodic memories.
234
+
235
+ Returns True if a new semantic memory was created.
236
+ """
237
+ # Sort by strength descending — strongest memory is the base
238
+ cluster.sort(key=lambda m: float(m.get("strength") or 0), reverse=True)
239
+
240
+ # Collect all unique entities across cluster
241
+ all_entities: Set[str] = set()
242
+ for mem in cluster:
243
+ for e in (mem.get("entities") or []):
244
+ all_entities.add(e)
245
+
246
+ # Build summary from strongest memory + additional entity context
247
+ base_content = cluster[0].get("content", "")
248
+ base_entities = set(cluster[0].get("entities") or [])
249
+ extra_entities = all_entities - base_entities
250
+
251
+ if extra_entities:
252
+ summary = f"[Distilled] {base_content} (also: {', '.join(sorted(extra_entities))})"
253
+ else:
254
+ summary = f"[Distilled] {base_content}"
255
+
256
+ source_ids = [m["id"] for m in cluster if m.get("id")]
257
+
258
+ # Create semantic memory node
259
+ create_query = (
260
+ "CREATE (m:Memory {"
261
+ " id: randomUUID(),"
262
+ " content: $content,"
263
+ " type: 'semantic',"
264
+ " importance: 1.0,"
265
+ " strength: 1.0,"
266
+ " recalls: 0,"
267
+ " created_at: datetime(),"
268
+ " accessed_at: datetime(),"
269
+ " provenance: $source_ids,"
270
+ " distilled: true"
271
+ "}) "
272
+ "WITH m "
273
+ "FOREACH (entity_name IN $entities | "
274
+ " MERGE (e:Entity {name: entity_name}) "
275
+ " CREATE (m)-[:MENTIONS]->(e) "
276
+ ") "
277
+ "RETURN m.id AS id"
278
+ )
279
+ rows = await self._execute(
280
+ create_query,
281
+ content=summary,
282
+ source_ids=source_ids,
283
+ entities=list(all_entities),
284
+ )
285
+ if not rows:
286
+ return False
287
+
288
+ semantic_id = rows[0].get("id", "")
289
+ logger.debug(
290
+ "Created semantic memory %s from %d episodic sources",
291
+ semantic_id, len(source_ids),
292
+ )
293
+
294
+ # Mark source memories as distilled
295
+ if source_ids:
296
+ await self._execute(
297
+ "MATCH (m:Memory) WHERE m.id IN $ids "
298
+ "SET m.distilled = true",
299
+ ids=source_ids,
300
+ )
301
+
302
+ return True
303
+
304
+ async def _execute(self, query: str, **params: Any) -> List[Dict[str, Any]]:
305
+ """Execute a Cypher query via the graph client."""
306
+ if hasattr(self.graph, "execute"):
307
+ result = await self.graph.execute(query, **params)
308
+ return result if result is not None else []
309
+
310
+ async with self.graph.driver.session(database=self.graph.database) as session:
311
+ result = await session.run(query, **params)
312
+ return [dict(record) async for record in result]
@@ -0,0 +1,129 @@
1
+ """Colony Graph Schema Migrations.
2
+
3
+ Applies Neo4j constraints and indexes required by the Colony graph memory
4
+ system. Designed to be idempotent and safe to re-run.
5
+
6
+ Vectors are maintained in a local LanceDB store in this implementation
7
+ (see apsimo/vector/), so these migrations create no vector index.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import logging
13
+ from typing import List
14
+
15
+ try:
16
+ from neo4j import AsyncDriver
17
+ except ImportError:
18
+ pass
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ # ──────────────────────────────────────────────────────────────────────
23
+ # Schema V1 — initial Colony graph schema
24
+ # ──────────────────────────────────────────────────────────────────────
25
+
26
+ # Each statement is executed individually so that one failure does not
27
+ # block subsequent (independent) statements.
28
+
29
+ SCHEMA_V1: List[str] = [
30
+ # ── Node constraints (id-based) ───────────────────────────────────
31
+ "CREATE CONSTRAINT memory_id IF NOT EXISTS FOR (m:Memory) REQUIRE m.id IS UNIQUE",
32
+ "CREATE CONSTRAINT person_id IF NOT EXISTS FOR (p:Person) REQUIRE p.id IS UNIQUE",
33
+ "CREATE CONSTRAINT entity_name IF NOT EXISTS FOR (e:Entity) REQUIRE e.name IS UNIQUE",
34
+ "CREATE CONSTRAINT owner_id IF NOT EXISTS FOR (o:Owner) REQUIRE o.id IS UNIQUE",
35
+ "CREATE CONSTRAINT signal_id IF NOT EXISTS FOR (s:Signal) REQUIRE s.id IS UNIQUE",
36
+ "CREATE CONSTRAINT context_id IF NOT EXISTS FOR (c:Context) REQUIRE c.id IS UNIQUE",
37
+ "CREATE CONSTRAINT score_event_id IF NOT EXISTS FOR (se:ScoreEvent) REQUIRE se.id IS UNIQUE",
38
+ "CREATE CONSTRAINT prediction_id IF NOT EXISTS FOR (pr:Prediction) REQUIRE pr.id IS UNIQUE",
39
+ "CREATE CONSTRAINT agent_id IF NOT EXISTS FOR (a:Agent) REQUIRE a.id IS UNIQUE",
40
+ "CREATE CONSTRAINT capability_id IF NOT EXISTS FOR (c:Capability) REQUIRE c.id IS UNIQUE",
41
+ "CREATE CONSTRAINT concept_id IF NOT EXISTS FOR (c:Concept) REQUIRE c.id IS UNIQUE",
42
+ "CREATE CONSTRAINT goal_id IF NOT EXISTS FOR (g:Goal) REQUIRE g.id IS UNIQUE",
43
+ "CREATE CONSTRAINT initiative_category_id IF NOT EXISTS FOR (ic:InitiativeCategory) REQUIRE ic.id IS UNIQUE",
44
+ "CREATE CONSTRAINT observation_id IF NOT EXISTS FOR (o:Observation) REQUIRE o.id IS UNIQUE",
45
+ "CREATE CONSTRAINT pattern_id IF NOT EXISTS FOR (p:Pattern) REQUIRE p.id IS UNIQUE",
46
+ "CREATE CONSTRAINT subsystem_id IF NOT EXISTS FOR (s:Subsystem) REQUIRE s.id IS UNIQUE",
47
+ "CREATE CONSTRAINT task_id IF NOT EXISTS FOR (t:Task) REQUIRE t.id IS UNIQUE",
48
+ # ── Indexes for common queries ────────────────────────────────────
49
+ "CREATE INDEX memory_type IF NOT EXISTS FOR (m:Memory) ON (m.type)",
50
+ "CREATE INDEX memory_strength IF NOT EXISTS FOR (m:Memory) ON (m.strength)",
51
+ "CREATE INDEX memory_accessed_at IF NOT EXISTS FOR (m:Memory) ON (m.accessed_at)",
52
+ "CREATE INDEX memory_created_at IF NOT EXISTS FOR (m:Memory) ON (m.created_at)",
53
+ # Synchronous full-text updates keep new/corrected source memories
54
+ # searchable while their independently maintained vectors catch up.
55
+ "CREATE FULLTEXT INDEX memory_content_fulltext IF NOT EXISTS FOR (m:Memory) ON EACH [m.content]",
56
+ "CREATE INDEX person_tier IF NOT EXISTS FOR (p:Person) ON (p.tier)",
57
+ "CREATE INDEX person_score IF NOT EXISTS FOR (p:Person) ON (p.score)",
58
+ "CREATE INDEX person_last_interaction IF NOT EXISTS FOR (p:Person) ON (p.lastInteraction)",
59
+ "CREATE INDEX signal_type IF NOT EXISTS FOR (s:Signal) ON (s.signal_type)",
60
+ "CREATE INDEX signal_timestamp IF NOT EXISTS FOR (s:Signal) ON (s.timestamp)",
61
+ "CREATE INDEX signal_processed IF NOT EXISTS FOR (s:Signal) ON (s.processed)",
62
+ "CREATE INDEX prediction_expires IF NOT EXISTS FOR (pr:Prediction) ON (pr.expires_at)",
63
+ "CREATE INDEX prediction_resolved IF NOT EXISTS FOR (pr:Prediction) ON (pr.resolved)",
64
+ "CREATE INDEX concept_confidence IF NOT EXISTS FOR (c:Concept) ON (c.confidence_score)",
65
+ "CREATE INDEX concept_status IF NOT EXISTS FOR (c:Concept) ON (c.status)",
66
+ "CREATE INDEX pattern_type IF NOT EXISTS FOR (p:Pattern) ON (p.pattern_type)",
67
+ "CREATE INDEX pattern_active IF NOT EXISTS FOR (p:Pattern) ON (p.is_active)",
68
+ "CREATE INDEX pattern_recurrence IF NOT EXISTS FOR (p:Pattern) ON (p.recurrence_count)",
69
+ "CREATE INDEX goal_status IF NOT EXISTS FOR (g:Goal) ON (g.status)",
70
+ "CREATE INDEX goal_priority IF NOT EXISTS FOR (g:Goal) ON (g.priority)",
71
+ "CREATE INDEX task_status IF NOT EXISTS FOR (t:Task) ON (t.status)",
72
+ "CREATE INDEX task_priority IF NOT EXISTS FOR (t:Task) ON (t.priority)",
73
+ "CREATE INDEX task_due IF NOT EXISTS FOR (t:Task) ON (t.due_at)",
74
+ "CREATE INDEX initiative_auto_exec IF NOT EXISTS FOR (ic:InitiativeCategory) ON (ic.auto_execute)",
75
+ "CREATE INDEX initiative_triggered IF NOT EXISTS FOR (ic:InitiativeCategory) ON (ic.last_triggered)",
76
+ "CREATE INDEX subsystem_status IF NOT EXISTS FOR (s:Subsystem) ON (s.status)",
77
+ "CREATE INDEX observation_created IF NOT EXISTS FOR (o:Observation) ON (o.created_at)",
78
+ "CREATE INDEX observation_entity IF NOT EXISTS FOR (o:Observation) ON (o.entity_id)",
79
+ # Memory governance indexes (v0.15.0)
80
+ "CREATE INDEX memory_source_type IF NOT EXISTS FOR (m:Memory) ON (m.source_type)",
81
+ "CREATE INDEX memory_epistemic_state IF NOT EXISTS FOR (m:Memory) ON (m.epistemic_state)",
82
+ "CREATE INDEX memory_effective_confidence IF NOT EXISTS FOR (m:Memory) ON (m.effective_confidence)",
83
+ "CREATE INDEX memory_content_hash IF NOT EXISTS FOR (m:Memory) ON (m.content_hash)",
84
+ "CREATE INDEX memory_protected IF NOT EXISTS FOR (m:Memory) ON (m.protected)",
85
+ ]
86
+
87
+ async def run_migrations(
88
+ driver: AsyncDriver,
89
+ database: str = "colony",
90
+ embedding_dimensions: int = 1536,
91
+ ) -> dict[str, int]:
92
+ """Apply all Colony graph schema migrations.
93
+
94
+ Args:
95
+ driver: An authenticated ``AsyncDriver`` instance.
96
+ database: Target Neo4j database name.
97
+ embedding_dimensions: Kept for API compat; vector index creation
98
+ is now handled by LanceDB (see colony/vector/).
99
+
100
+ Returns:
101
+ A summary dict with counts of ``applied``, ``skipped``, and
102
+ ``failed`` statements.
103
+ """
104
+ applied = 0
105
+ skipped = 0
106
+ failed = 0
107
+
108
+ async with driver.session(database=database) as session:
109
+ # ── Constraints & indexes ─────────────────────────────────────
110
+ for stmt in SCHEMA_V1:
111
+ try:
112
+ await session.run(stmt)
113
+ applied += 1
114
+ except Exception as exc:
115
+ msg = str(exc).lower()
116
+ if "already exists" in msg or "equivalent" in msg:
117
+ skipped += 1
118
+ else:
119
+ failed += 1
120
+
121
+ # Vector index creation removed — vector search now uses local LanceDB.
122
+ # Neo4j Community Edition does not support db.index.vector.* procedures.
123
+ logger.info(
124
+ "Graph migrations complete (applied=%d, skipped=%d, failed=%d). "
125
+ "Vector search handled by LanceDB — run 'colony vector setup' to configure.",
126
+ applied, skipped, failed,
127
+ )
128
+
129
+ return {"applied": applied, "skipped": skipped, "failed": failed}
@@ -0,0 +1,248 @@
1
+ """Colony Graph Cypher Query Templates.
2
+
3
+ All Cypher queries used by the Colony intelligence layer are defined here
4
+ as module-level constants. This keeps query text out of business logic
5
+ and makes it easy to test / review / optimise in one place.
6
+
7
+ Parameters are referenced with ``$param`` syntax for Neo4j driver binding.
8
+ """
9
+
10
+ # ──────────────────────────────────────────────────────────────────────
11
+ # Memory operations
12
+ # ──────────────────────────────────────────────────────────────────────
13
+
14
+ STORE_MEMORY = """\
15
+ CREATE (m:Memory {
16
+ id: randomUUID(),
17
+ content: $content,
18
+ type: $memory_type,
19
+ strength: 1.0,
20
+ created_at: datetime(),
21
+ accessed_at: datetime(),
22
+ embedding: $embedding,
23
+ metadata: $metadata
24
+ })
25
+ WITH m
26
+ UNWIND $entities AS entity_name
27
+ MERGE (e:Entity {name: entity_name})
28
+ CREATE (m)-[:MENTIONS]->(e)
29
+ RETURN m.id AS id
30
+ """
31
+
32
+ RECALL_BY_ENTITY = """\
33
+ MATCH (e:Entity {name: $entity_name})<-[:MENTIONS]-(m:Memory)
34
+ WHERE m.strength >= $min_strength
35
+ RETURN m {.*, entity: e.name} AS memory
36
+ ORDER BY m.strength DESC, m.accessed_at DESC
37
+ LIMIT $limit
38
+ """
39
+
40
+ RECALL_BY_TYPE = """\
41
+ MATCH (m:Memory {type: $memory_type})
42
+ WHERE m.strength >= $min_strength
43
+ RETURN m {.*} AS memory
44
+ ORDER BY m.strength DESC, m.created_at DESC
45
+ LIMIT $limit
46
+ """
47
+
48
+ # ──────────────────────────────────────────────────────────────────────
49
+ # Decay & pruning
50
+ # ──────────────────────────────────────────────────────────────────────
51
+
52
+ DECAY_ALL = """\
53
+ MATCH (m:Memory)
54
+ WITH m,
55
+ duration.between(m.accessed_at, datetime()).days AS days_since
56
+ SET m.strength = m.strength * (0.5 ^ (toFloat(days_since) / $half_life))
57
+ """
58
+
59
+ PRUNE_WEAK_MEMORIES = """\
60
+ MATCH (m:Memory)
61
+ WHERE m.strength < $threshold
62
+ DETACH DELETE m
63
+ RETURN count(m) AS pruned
64
+ """
65
+
66
+ TOUCH_MEMORY = """\
67
+ MATCH (m:Memory {id: $memory_id})
68
+ SET m.accessed_at = datetime(),
69
+ m.strength = CASE
70
+ WHEN m.strength + 0.1 > 1.0 THEN 1.0
71
+ ELSE m.strength + 0.1
72
+ END
73
+ RETURN m {.*} AS memory
74
+ """
75
+
76
+ # ──────────────────────────────────────────────────────────────────────
77
+ # Person / signal queries
78
+ # ──────────────────────────────────────────────────────────────────────
79
+
80
+ GET_PERSON_WITH_SIGNALS = """\
81
+ MATCH (p:Person {id: $person_id})
82
+ OPTIONAL MATCH (p)-[:EXHIBITED]->(s:Signal)
83
+ WHERE s.timestamp >= datetime() - duration({days: 7})
84
+ WITH p, collect(s) AS signals
85
+ OPTIONAL MATCH (p)-[:HAS_CONTEXT]->(c:Context)
86
+ WHERE c.end_date >= date() OR c.end_date IS NULL
87
+ RETURN p {.*, signals: signals, contexts: collect(c)}
88
+ """
89
+
90
+ GET_PERSON_SIGNALS_IN_WINDOW = """\
91
+ MATCH (p:Person {id: $person_id})-[:EXHIBITED]->(s:Signal)
92
+ WHERE s.timestamp >= datetime($cutoff)
93
+ RETURN s.signal_type AS type,
94
+ s.normalized_value AS value,
95
+ s.timestamp AS ts
96
+ ORDER BY s.timestamp DESC
97
+ """
98
+
99
+ STORE_SIGNAL = """\
100
+ MERGE (p:Person {id: $person_id})
101
+ CREATE (s:Signal {
102
+ id: randomUUID(),
103
+ signal_type: $signal_type,
104
+ raw_value: $raw_value,
105
+ normalized_value: $normalized_value,
106
+ timestamp: datetime($timestamp),
107
+ source: $source
108
+ })
109
+ CREATE (p)-[:EXHIBITED]->(s)
110
+ RETURN s.id AS id
111
+ """
112
+
113
+ # ──────────────────────────────────────────────────────────────────────
114
+ # Relationship scoring
115
+ # ──────────────────────────────────────────────────────────────────────
116
+
117
+ COMPUTE_RELATIONSHIP_SCORES = """\
118
+ MATCH (p:Person)
119
+ WHERE p.lastInteraction >= datetime() - duration({days: 90})
120
+ MATCH (p)-[:EXHIBITED]->(s:Signal)
121
+ WHERE s.timestamp >= datetime() - duration({days: 90})
122
+ WITH p, s.signal_type AS type,
123
+ avg(s.normalized_value) AS avg_value,
124
+ count(s) AS signal_count
125
+ WITH p, collect({type: type, avg: avg_value, count: signal_count}) AS signals
126
+ RETURN p.id, p.name, signals
127
+ """
128
+
129
+ RECORD_SCORE_CHANGE = """\
130
+ MATCH (p:Person {id: $person_id})
131
+ SET p.score = $new_score,
132
+ p.tier = $new_tier,
133
+ p.lastInteraction = datetime()
134
+ WITH p
135
+ CREATE (se:ScoreEvent {
136
+ id: randomUUID(),
137
+ score: $new_score,
138
+ tier: $new_tier,
139
+ delta: $delta,
140
+ reason: $reason,
141
+ createdAt: datetime()
142
+ })
143
+ CREATE (p)-[:SCORE_CHANGED]->(se)
144
+ RETURN se.id AS id
145
+ """
146
+
147
+ # ──────────────────────────────────────────────────────────────────────
148
+ # Relationship maintenance
149
+ # ──────────────────────────────────────────────────────────────────────
150
+
151
+ FIND_NEGLECTED_RELATIONSHIPS = """\
152
+ MATCH (p:Person)
153
+ WHERE p.tier IN ['inner_circle', 'trusted']
154
+ AND p.lastInteraction < datetime() - duration({days: 14})
155
+ RETURN p.id, p.name, p.tier, p.lastInteraction,
156
+ duration.between(p.lastInteraction, datetime()).days AS days_since
157
+ ORDER BY days_since DESC
158
+ LIMIT $limit
159
+ """
160
+
161
+ FIND_NEGLECTED_BY_TIER = """\
162
+ MATCH (p:Person)
163
+ WHERE p.tier = $tier
164
+ AND p.lastInteraction < datetime() - duration({days: $days_threshold})
165
+ RETURN p.id AS id, p.name AS name, p.tier AS tier,
166
+ p.lastInteraction AS last_interaction,
167
+ duration.between(p.lastInteraction, datetime()).days AS days_since
168
+ ORDER BY days_since DESC
169
+ """
170
+
171
+ # ──────────────────────────────────────────────────────────────────────
172
+ # Traversal / graph exploration
173
+ # ──────────────────────────────────────────────────────────────────────
174
+
175
+ TRAVERSE_MEMORY_CONNECTIONS = """\
176
+ MATCH path = (m1:Memory)-[:CAUSED_BY|LED_TO|SUPPORTS*1..3]->(m2:Memory)
177
+ WHERE m1.id = $memory_id
178
+ AND all(node IN nodes(path) WHERE node.strength >= $min_strength)
179
+ RETURN m2 {.*} AS memory,
180
+ length(path) AS distance,
181
+ reduce(w = 1.0, r IN relationships(path) | w * r.weight) AS path_weight
182
+ ORDER BY path_weight DESC
183
+ LIMIT $limit
184
+ """
185
+
186
+ FIND_SHARED_ENTITIES = """\
187
+ MATCH (m1:Memory {id: $memory_id})-[:MENTIONS]->(e:Entity)<-[:MENTIONS]-(m2:Memory)
188
+ WHERE m1 <> m2
189
+ AND m2.strength >= $min_strength
190
+ RETURN m2 {.*, shared_entity: e.name} AS memory
191
+ ORDER BY m2.strength DESC
192
+ LIMIT $limit
193
+ """
194
+
195
+ # ──────────────────────────────────────────────────────────────────────
196
+ # Owner / setup
197
+ # ──────────────────────────────────────────────────────────────────────
198
+
199
+ ENSURE_OWNER = """\
200
+ MERGE (o:Owner {id: $owner_id})
201
+ ON CREATE SET o.name = $name,
202
+ o.timezone = $timezone,
203
+ o.created_at = datetime()
204
+ RETURN o {.*} AS owner
205
+ """
206
+
207
+ LINK_PERSON_TO_OWNER = """\
208
+ MATCH (o:Owner {id: $owner_id})
209
+ MERGE (p:Person {id: $person_id})
210
+ ON CREATE SET p.name = $name,
211
+ p.tier = $tier,
212
+ p.score = 0.0,
213
+ p.created_at = datetime()
214
+ MERGE (o)-[:KNOWS]->(p)
215
+ RETURN p {.*} AS person
216
+ """
217
+
218
+
219
+ # ──────────────────────────────────────────────────────────────────────
220
+ # Baseline queries (GraphBaselineStore)
221
+ # ──────────────────────────────────────────────────────────────────────
222
+
223
+ GET_BASELINE = """\
224
+ MATCH (p:Person {id: $person_id})
225
+ RETURN p.baseline_msg_count AS msg_count,
226
+ p.baseline_length_mean AS length_mean,
227
+ p.baseline_length_m2 AS length_m2,
228
+ p.baseline_length_std AS length_std,
229
+ p.baseline_hour_histogram AS hour_histogram
230
+ """
231
+
232
+ UPDATE_BASELINE = """\
233
+ MERGE (p:Person {id: $person_id})
234
+ ON CREATE SET p.baseline_msg_count = 0,
235
+ p.baseline_length_mean = 0.0,
236
+ p.baseline_length_m2 = 0.0,
237
+ p.baseline_length_std = 0.0,
238
+ p.baseline_hour_histogram = '[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]',
239
+ p.baseline_updated_at = datetime(),
240
+ p.created_at = datetime()
241
+ SET p.baseline_msg_count = $msg_count,
242
+ p.baseline_length_mean = $length_mean,
243
+ p.baseline_length_m2 = $length_m2,
244
+ p.baseline_length_std = $length_std,
245
+ p.baseline_hour_histogram = $hour_histogram,
246
+ p.baseline_updated_at = datetime()
247
+ RETURN p.id AS id
248
+ """