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,337 @@
1
+ """Colony Graph Schema — Node and edge type definitions.
2
+
3
+ Every node and relationship type used in the Colony Neo4j graph is modelled
4
+ here as a Pydantic ``BaseModel`` (for validation / serialisation) together
5
+ with string‐constant edge types.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from datetime import date, datetime
11
+ from enum import Enum
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ from pydantic import BaseModel, Field
15
+
16
+
17
+ # ──────────────────────────────────────────────────────────────────────
18
+ # Trust tiers (mirrors RelationshipScorer thresholds)
19
+ # ──────────────────────────────────────────────────────────────────────
20
+
21
+ class TrustTier(str, Enum):
22
+ INNER_CIRCLE = "inner_circle"
23
+ TRUSTED = "trusted"
24
+ REGULAR = "regular"
25
+ PERIPHERAL = "peripheral"
26
+ SILENCED = "silenced"
27
+
28
+
29
+ # ──────────────────────────────────────────────────────────────────────
30
+ # Node types
31
+ # ──────────────────────────────────────────────────────────────────────
32
+
33
+ class Owner(BaseModel):
34
+ """The Colony owner (singleton node — one per graph)."""
35
+
36
+ id: str = Field(..., description="Unique owner identifier")
37
+ name: str
38
+ timezone: str = "UTC"
39
+ created_at: datetime = Field(default_factory=datetime.utcnow)
40
+
41
+
42
+ class Agent(BaseModel):
43
+ """An autonomous entity (Colony itself, or other agents/bots)."""
44
+
45
+ id: str = Field(..., description="Unique agent identifier")
46
+ name: str
47
+ version: Optional[str] = None
48
+ status: str = "active"
49
+ capabilities: List[str] = Field(default_factory=list)
50
+ health_score: float = Field(default=1.0, ge=0.0, le=1.0)
51
+ last_tick_at: Optional[datetime] = None
52
+ created_at: datetime = Field(default_factory=datetime.utcnow)
53
+
54
+
55
+ class Subsystem(BaseModel):
56
+ """A Colony component that can be monitored and restarted."""
57
+
58
+ id: str = Field(..., description="Unique subsystem identifier")
59
+ name: str
60
+ status: str = "active"
61
+ latency_ms: Optional[float] = None
62
+ error_rate: Optional[float] = None
63
+ last_check_at: Optional[datetime] = None
64
+ created_at: datetime = Field(default_factory=datetime.utcnow)
65
+
66
+
67
+ class Capability(BaseModel):
68
+ """A tool or skill that Colony has or needs."""
69
+
70
+ id: str = Field(..., description="Unique capability identifier")
71
+ name: str
72
+ description: Optional[str] = None
73
+ available: bool = True
74
+ status: str = "available" # available | deprecated | missing | planned
75
+ failure_count: int = 0
76
+ last_failure_at: Optional[datetime] = None
77
+ created_at: datetime = Field(default_factory=datetime.utcnow)
78
+
79
+
80
+ class Project(BaseModel):
81
+ """An active work item."""
82
+
83
+ id: str = Field(..., description="Unique project identifier")
84
+ name: str
85
+ description: Optional[str] = None
86
+ status: str = "active"
87
+ created_at: datetime = Field(default_factory=datetime.utcnow)
88
+
89
+
90
+ class Goal(BaseModel):
91
+ """A goal or objective."""
92
+
93
+ id: str = Field(..., description="Unique goal identifier")
94
+ title: str
95
+ description: Optional[str] = None
96
+ status: str = "active"
97
+ priority: float = Field(default=0.5, ge=0.0, le=1.0)
98
+ created_at: datetime = Field(default_factory=datetime.utcnow)
99
+
100
+
101
+ class Task(BaseModel):
102
+ """An actionable work unit."""
103
+
104
+ id: str = Field(..., description="Unique task identifier")
105
+ title: str
106
+ description: Optional[str] = None
107
+ status: str = "pending"
108
+ priority: float = Field(default=0.5, ge=0.0, le=1.0)
109
+ created_at: datetime = Field(default_factory=datetime.utcnow)
110
+
111
+
112
+ class Pattern(BaseModel):
113
+ """A recurring behavioral pattern."""
114
+
115
+ id: str = Field(..., description="Unique pattern identifier")
116
+ name: str
117
+ description: Optional[str] = None
118
+ confidence: float = Field(default=0.5, ge=0.0, le=1.0)
119
+ occurrences: int = 0
120
+ pattern_type: str = "behavioral" # behavioral | workflow | preference | correction
121
+ trigger: Optional[str] = None
122
+ action: Optional[str] = None
123
+ recurrence_count: int = 0
124
+ last_triggered_at: Optional[datetime] = None
125
+ is_active: bool = True
126
+ created_at: datetime = Field(default_factory=datetime.utcnow)
127
+
128
+
129
+ class Concept(BaseModel):
130
+ """A knowledge domain or concept Colony has encountered."""
131
+
132
+ id: str = Field(..., description="Unique concept identifier")
133
+ name: str
134
+ domain: str = "general" # e.g., "technology", "science", "person"
135
+ description: Optional[str] = None
136
+ confidence_score: float = 0.0 # 0 = unknown, 1 = expert
137
+ encounter_count: int = 0
138
+ last_researched_at: Optional[datetime] = None
139
+ last_encountered_at: Optional[datetime] = None
140
+ source: Optional[str] = None # "web_search", "tool_failure", "owner_query"
141
+ status: str = "open" # open | researching | learned | archived
142
+ created_at: datetime = Field(default_factory=datetime.utcnow)
143
+
144
+
145
+ class Preference(BaseModel):
146
+ """A learned preference or behavioral rule."""
147
+
148
+ id: str = Field(..., description="Unique preference identifier")
149
+ trigger: str
150
+ expected: str
151
+ source: str = "behavioral_correction" # behavioral_correction, owner_config, inferred
152
+ created_at: datetime = Field(default_factory=datetime.utcnow)
153
+ updated_at: Optional[datetime] = None
154
+
155
+
156
+ class InitiativeCategory(BaseModel):
157
+ """A dynamic self-initiative category registered at runtime."""
158
+
159
+ id: str = Field(..., description="Unique category identifier")
160
+ name: str
161
+ description: Optional[str] = None
162
+ trigger_query: Optional[str] = None
163
+ action_type: str = "auto_fix" # auto_fix, propose, research, notify
164
+ executor_skill: str
165
+ priority_formula: Optional[str] = None
166
+ cooldown_minutes: int = 30
167
+ auto_execute: bool = True
168
+ requires_approval: bool = False
169
+ effectiveness_score: float = Field(default=0.5, ge=0.0, le=1.0)
170
+ total_triggered: int = 0
171
+ total_successful: int = 0
172
+ created_at: datetime = Field(default_factory=datetime.utcnow)
173
+ updated_at: Optional[datetime] = None
174
+
175
+
176
+ class Person(BaseModel):
177
+ """A person in the owner's relationship network."""
178
+
179
+ id: str = Field(..., description="Unique person identifier (UUID)")
180
+ name: str
181
+ tier: TrustTier = TrustTier.PERIPHERAL
182
+ score: float = Field(default=0.0, ge=0.0, le=100.0)
183
+ last_interaction: Optional[datetime] = None
184
+ contact_info: Optional[Dict[str, str]] = None
185
+ created_at: datetime = Field(default_factory=datetime.utcnow)
186
+
187
+
188
+ class Memory(BaseModel):
189
+ """An episodic / semantic / procedural memory."""
190
+
191
+ id: str = Field(..., description="UUID assigned by Neo4j randomUUID()")
192
+ content: str
193
+ type: str = Field(..., description="e.g. episodic, semantic, procedural")
194
+ strength: float = Field(default=1.0, ge=0.0, le=1.0)
195
+ embedding: Optional[List[float]] = None
196
+ metadata: Optional[Dict[str, Any]] = None
197
+ sources: Optional[List[str]] = None
198
+ created_at: datetime = Field(default_factory=datetime.utcnow)
199
+ accessed_at: datetime = Field(default_factory=datetime.utcnow)
200
+
201
+
202
+ class Entity(BaseModel):
203
+ """A named entity extracted from memories (person, place, concept …)."""
204
+
205
+ name: str = Field(..., description="Canonical entity name (unique)")
206
+ entity_type: Optional[str] = None # person, place, org, concept
207
+ first_seen: datetime = Field(default_factory=datetime.utcnow)
208
+
209
+
210
+ class Signal(BaseModel):
211
+ """A single behavioral signal emitted by a Person."""
212
+
213
+ id: str
214
+ signal_type: str # message_length, sentiment, response_latency, …
215
+ raw_value: float
216
+ normalized_value: float
217
+ timestamp: datetime
218
+ source: str # message, reaction, call
219
+ context: Optional[Dict[str, Any]] = None
220
+
221
+
222
+ class Context(BaseModel):
223
+ """Temporal context attached to a Person (job change, vacation, …)."""
224
+
225
+ id: str
226
+ label: str
227
+ description: Optional[str] = None
228
+ start_date: date
229
+ end_date: Optional[date] = None
230
+ active: bool = True
231
+
232
+
233
+ class ScoreEvent(BaseModel):
234
+ """Audit record for a relationship score change."""
235
+
236
+ id: str
237
+ score: float
238
+ tier: TrustTier
239
+ delta: float
240
+ reason: str
241
+ created_at: datetime = Field(default_factory=datetime.utcnow)
242
+
243
+
244
+ class Prediction(BaseModel):
245
+ """A forward‐looking behavioural prediction."""
246
+
247
+ id: str
248
+ prediction_type: str # timing, need, action, trajectory
249
+ description: str
250
+ probability: float = Field(ge=0.0, le=1.0)
251
+ person_id: str
252
+ reasoning: List[str] = Field(default_factory=list)
253
+ expires_at: datetime
254
+ resolved: Optional[bool] = None
255
+ created_at: datetime = Field(default_factory=datetime.utcnow)
256
+
257
+
258
+ # ──────────────────────────────────────────────────────────────────────
259
+ # Edge (relationship) types
260
+ # ──────────────────────────────────────────────────────────────────────
261
+
262
+ class EdgeType(str, Enum):
263
+ """All relationship types in the Colony graph."""
264
+
265
+ # Owner ↔ Person
266
+ KNOWS = "KNOWS"
267
+
268
+ # Memory → Entity
269
+ MENTIONS = "MENTIONS"
270
+
271
+ # Person → Signal
272
+ EXHIBITED = "EXHIBITED"
273
+
274
+ # Person → Context
275
+ HAS_CONTEXT = "HAS_CONTEXT"
276
+
277
+ # Person → ScoreEvent
278
+ SCORE_CHANGED = "SCORE_CHANGED"
279
+
280
+ # Person → Prediction
281
+ PREDICTED = "PREDICTED"
282
+
283
+ # Memory → Memory (causal / logical chains)
284
+ CAUSED_BY = "CAUSED_BY"
285
+ LED_TO = "LED_TO"
286
+ SUPPORTS = "SUPPORTS"
287
+ MERGED_INTO = "MERGED_INTO"
288
+
289
+ # Owner → Memory (ownership)
290
+ REMEMBERS = "REMEMBERS"
291
+
292
+ # Memory → Person (memory about a person)
293
+ ABOUT = "ABOUT"
294
+
295
+ # Agent → Person (agent manages relationship with person)
296
+ MANAGES = "MANAGES"
297
+
298
+ # Person → Project (person owns/works on project)
299
+ OWNS = "OWNS"
300
+
301
+ # Subsystem → Subsystem (component dependency)
302
+ DEPENDS_ON = "DEPENDS_ON"
303
+
304
+ # Agent → Capability (agent has tool)
305
+ HAS_CAPABILITY = "HAS_CAPABILITY"
306
+
307
+ # Agent → Capability (agent lacks tool)
308
+ NEEDS_CAPABILITY = "NEEDS_CAPABILITY"
309
+
310
+ # Agent → Initiative (agent created initiative)
311
+ GENERATED = "GENERATED"
312
+
313
+ # Initiative → Subsystem (initiative targets component)
314
+ TARGETS = "TARGETS"
315
+
316
+ # Task → Project (task belongs to project)
317
+ BELONGS_TO = "BELONGS_TO"
318
+
319
+ # Goal → Goal (goal blocks another)
320
+ BLOCKS = "BLOCKS"
321
+
322
+ # Person → Pattern (person exhibits pattern)
323
+ EXHIBITS = "EXHIBITS"
324
+
325
+ # Pattern → InitiativeCategory (pattern triggers category)
326
+ TRIGGERS = "TRIGGERS"
327
+
328
+
329
+ # ──────────────────────────────────────────────────────────────────────
330
+ # Convenience exports
331
+ # ──────────────────────────────────────────────────────────────────────
332
+
333
+ NODE_TYPES = (
334
+ Owner, Person, Memory, Entity, Signal, Context, ScoreEvent, Prediction,
335
+ Agent, Subsystem, Capability, Project, Goal, Task, Pattern, Concept, Preference, InitiativeCategory,
336
+ )
337
+ EDGE_TYPES = tuple(EdgeType)
@@ -0,0 +1,252 @@
1
+ """Shared bounded reranking for authorized belief and source candidates."""
2
+ from __future__ import annotations
3
+
4
+ import asyncio
5
+ import logging
6
+ import math
7
+ import os
8
+ import re
9
+ import time
10
+ from typing import Any, Dict, List
11
+
12
+
13
+ def current_work_query(query):
14
+ """Recognize explicit present-work questions, retaining ambiguous requests.
15
+
16
+ This is a narrow selection hint, not authority or a semantic classifier.
17
+ History, comparisons and requests for instructions still need old answers.
18
+ """
19
+ if not isinstance(query, str) or len(query) > 8000:
20
+ return False
21
+ text = re.sub(r"^\s*\[[^\]\n]{1,512}\]\s*", "", query).strip().lower()
22
+ if re.search(r"\b(yesterday|histor(?:y|ical)|previous(?:ly)?|earlier|before|then|"
23
+ r"last (?:time|week|month|year)|used to|compar(?:ed?|ing|ison)|versus|"
24
+ r"how (?:to|do|can|should)|procedure|playbook|recipe|steps|"
25
+ r"(?:give|provide|explain|show|need|include|use|follow|recall) (?:the |your |me )?instructions)\b", text):
26
+ return False
27
+ return bool(re.match(
28
+ r"(?:what are you (?:currently (?:doing|working on)|"
29
+ r"(?:doing|working on) (?:right now|now|currently))\b|"
30
+ r"what (?:work|tasks|sessions|jobs|crons|workers) (?:are|is) "
31
+ r"(?:currently |now )?(?:running|active|in flight)\b)", text))
32
+
33
+
34
+ class RecallSelector:
35
+ def __init__(self, rerank_fn=None, *, calibration_metadata=None, logger=None):
36
+ self._rerank_fn = rerank_fn
37
+ self._rerank_calibration_metadata = calibration_metadata
38
+ self.logger = logger or logging.getLogger(__name__)
39
+
40
+ async def select_context(self, query, beliefs, quotations, *, limit=5, max_chars=6000,
41
+ current_work_available=False):
42
+ """One rank fusion, reranking pass and budget after authority checks."""
43
+ from .recall import fuse_candidates, pack_memory_context
44
+ beliefs = [dict(row, kind="belief") for row in beliefs]
45
+ # Semantic retrieval can return the same words from many turns. Collapse
46
+ # only plain quotations by the same known speaker, after scoped claim
47
+ # expansion and time filtering. Keep the first occurrence's intact
48
+ # lineage; assertion/conflict bundles, dated events and uncertain
49
+ # attribution survive. A time-qualified query may need both occurrences.
50
+ unique, seen = [], set()
51
+ omit_status_replies = current_work_available and current_work_query(query)
52
+ for row in quotations:
53
+ # Only canonical request/answer pairing can identify an old status
54
+ # reply. Never use quotation text alone or a client owner flag.
55
+ if (omit_status_replies
56
+ and row.get('_current_work_status_reply') is True
57
+ and row.get('kind') == 'source_quote' and row.get('role') == 'assistant'
58
+ and row.get('scope') == 'person'
59
+ and row.get('epistemic_state') == 'quotation'
60
+ and not any(row.get(key) for key in (
61
+ 'atomic_evidence', 'validity_status', 'procedure_context', '_annotation_ids'))):
62
+ continue
63
+ if (row.get("kind") == "source_quote" and row.get("epistemic_state") == "quotation"
64
+ and not row.get("atomic_evidence") and row.get("scope") == "person"
65
+ and not row.get("validity_status")
66
+ and row.get("contact_id") and row.get("role") in {"user", "assistant"}):
67
+ key = (row["contact_id"], row["role"], row["content"])
68
+ if key in seen:
69
+ continue
70
+ seen.add(key)
71
+ unique.append(row)
72
+ quotations = unique
73
+ # Media is an independent candidate producer. Appending its first hit
74
+ # after every text hit can exclude it from the bounded reranker before
75
+ # relevance is assessed. Fuse its rank independently; it still shares
76
+ # the same reranker, abstention threshold and final context budget.
77
+ media = [row for row in quotations if row.get("kind") == "media_description"]
78
+ text = [row for row in quotations if row.get("kind") != "media_description"]
79
+ # Confidence in a belief and certainty that words were quoted are not
80
+ # comparable truth scores. Preserve them as evidence metadata; select
81
+ # across kinds by rank and semantic relevance alone.
82
+ candidates = fuse_candidates(
83
+ beliefs, text, limit=len(beliefs) + len(quotations),
84
+ confidence_weighting=False, additional=(media,))
85
+ ranked = await self.rerank(
86
+ query, candidates, limit, confidence_weighting=False,
87
+ candidate_limit=max(1, 4 * limit))
88
+ ranked.sort(key=lambda row: row.get("relevance", 0), reverse=True)
89
+ return pack_memory_context(ranked, limit=limit, max_chars=max_chars)
90
+
91
+ async def rerank(
92
+ self,
93
+ query: str,
94
+ memories: List[Dict[str, Any]],
95
+ limit: int,
96
+ *,
97
+ strength_ranking: bool = False,
98
+ confidence_weighting: bool = True,
99
+ candidate_limit: int | None = None,
100
+ ) -> List[Dict[str, Any]]:
101
+ """Cross-encoder rerank of filtered recall candidates, bounded and
102
+ fail-open.
103
+
104
+ COLONY_RECALL_RERANK gates it: ``off`` (default) never calls the
105
+ reranker; ``shadow`` scores and logs the rank delta but returns the
106
+ candidate order untouched (measure p95 before flipping); ``on`` replaces the
107
+ vector score in the relevance blend with the rerank score. The call
108
+ is inline but hard-capped by COLONY_RECALL_RERANK_TIMEOUT_MS
109
+ (default 1200). On timeout or error, recall keeps the candidate order
110
+ and marks selection unavailable. A candidate set that already fits
111
+ skips reranking only when no calibrated abstention cutoff is active.
112
+ A candidate limit bounds model work, while preserving the full input
113
+ for disabled, shadow and failed selection.
114
+ """
115
+ mode = os.environ.get("COLONY_RECALL_RERANK", "off").strip().lower()
116
+ if mode not in ("shadow", "on"):
117
+ return memories
118
+ min_score = None
119
+ raw_min_score = os.environ.get("COLONY_RECALL_RERANK_MIN_SCORE", "").strip()
120
+ if raw_min_score:
121
+ try:
122
+ value = float(raw_min_score)
123
+ if math.isfinite(value):
124
+ min_score = value
125
+ except (TypeError, ValueError):
126
+ pass
127
+ if min_score is not None:
128
+ from .recall import calibration_fingerprint
129
+ metadata_fn = getattr(self, "_rerank_calibration_metadata", None)
130
+ try:
131
+ metadata = metadata_fn() if metadata_fn is not None else None
132
+ actual = calibration_fingerprint(metadata) if metadata else None
133
+ except Exception:
134
+ metadata, actual = None, None
135
+ expected = os.environ.get("COLONY_RECALL_RERANK_CALIBRATION", "").strip()
136
+ if not actual or not expected or actual != expected:
137
+ status = "mismatch" if expected and actual else "unverified"
138
+ min_score = None
139
+ warning_key = (actual, expected)
140
+ if getattr(self, "_rerank_calibration_warned", None) != warning_key:
141
+ self._rerank_calibration_warned = warning_key
142
+ self.logger.warning("Rerank abstention calibration %s; threshold disabled (current configuration: %s)", status, actual or "unknown")
143
+ else:
144
+ status = ("configuration_verified" if metadata.get("weights_revision")
145
+ and metadata["weights_revision"] != "unverified"
146
+ else "configuration_verified_weights_unverified")
147
+ for memory in memories:
148
+ memory["rerank_calibration"] = status
149
+ rerank_fn = getattr(self, "_rerank_fn", None)
150
+ if rerank_fn is None:
151
+ for memory in memories:
152
+ memory["rerank_status"] = "unavailable"
153
+ if rerank_fn is None or not memories or (len(memories) <= limit and min_score is None):
154
+ return memories
155
+ try:
156
+ timeout_ms = float(os.environ.get(
157
+ "COLONY_RECALL_RERANK_TIMEOUT_MS", "1200"))
158
+ except (TypeError, ValueError):
159
+ timeout_ms = 1200.0
160
+
161
+ # Combined recall fuses several producers. Overfetch relative to the
162
+ # packet size without making the inline model score every producer's
163
+ # entire result set. Keep the full list available for fallback.
164
+ submitted = memories if candidate_limit is None else memories[:candidate_limit]
165
+ docs = [str(m.get("ranking_text", m.get("content", ""))) for m in submitted]
166
+ try:
167
+ results = await asyncio.wait_for(
168
+ rerank_fn(query, docs, top_k=len(docs)),
169
+ timeout=max(timeout_ms, 1.0) / 1000.0,
170
+ )
171
+ except Exception as exc:
172
+ self._warn_rerank_failure(exc)
173
+ for memory in memories:
174
+ memory["rerank_status"] = "unavailable"
175
+ return memories
176
+
177
+ scores: Dict[int, float] = {}
178
+ try:
179
+ for r in results or []:
180
+ idx = r.get("index") if isinstance(r, dict) else getattr(r, "index", None)
181
+ score = r.get("score") if isinstance(r, dict) else getattr(r, "score", None)
182
+ if not isinstance(idx, int) or isinstance(idx, bool) or idx in scores:
183
+ raise ValueError("reranker returned an invalid or duplicate index")
184
+ score = float(score)
185
+ if not 0 <= idx < len(submitted) or not math.isfinite(score):
186
+ raise ValueError("reranker returned an invalid score")
187
+ scores[idx] = score
188
+ # We requested every submitted document. A partial response cannot
189
+ # mix cross-encoder scores with original rank-fusion/ANN scores, or
190
+ # silently treat missing relevance judgments as abstention.
191
+ if len(scores) != len(submitted):
192
+ raise ValueError("reranker returned incomplete scores")
193
+ except (TypeError, ValueError, OverflowError) as exc:
194
+ self._warn_rerank_failure(exc)
195
+ for memory in memories:
196
+ memory["rerank_status"] = "unavailable"
197
+ return memories
198
+
199
+ if mode == "shadow":
200
+ ann_top = [m.get("id") for m in sorted(
201
+ memories, key=lambda m: m.get("relevance", 0),
202
+ reverse=True)][:limit]
203
+ rr_idx = sorted(range(len(submitted)),
204
+ key=lambda i: scores.get(i, float("-inf")),
205
+ reverse=True)
206
+ rr_top = [submitted[i].get("id") for i in rr_idx[:limit]]
207
+ moved = sum(1 for a, b in zip(ann_top, rr_top) if a != b)
208
+ self.logger.info(
209
+ "recall rerank shadow: candidates=%d limit=%d "
210
+ "top_overlap=%d/%d positions_changed=%d",
211
+ len(submitted), limit, len(set(ann_top) & set(rr_top)),
212
+ limit, moved)
213
+ return memories
214
+
215
+ # mode == "on": rerank score replaces the vector score in the blend.
216
+ # The unsubmitted tail has no comparable model score and cannot enter
217
+ # a successfully reranked packet.
218
+ memories = submitted
219
+ for i, mem in enumerate(memories):
220
+ effective_confidence = (float(
221
+ mem.get("effective_confidence", mem.get("strength", 1.0)))
222
+ if confidence_weighting else 1.0)
223
+ relevance = scores[i] * effective_confidence
224
+ if strength_ranking:
225
+ relevance *= 0.5 + 0.5 * float(mem.get("strength", 1.0))
226
+ mem["relevance"] = relevance
227
+ mem["rerank_score"] = scores[i]
228
+ mem["rerank_status"] = "scored"
229
+ if min_score is not None:
230
+ # Do not fill the context window with unrelated passages merely
231
+ # because there are fewer candidates than requested. Calibration
232
+ # belongs to the serving model/deployment, not a universal constant.
233
+ memories = [mem for i, mem in enumerate(memories)
234
+ if i in scores and scores[i] >= min_score]
235
+ return memories
236
+
237
+ def _warn_rerank_failure(self, exc: BaseException) -> None:
238
+ """Warn on rerank failure at most once per ~5 minutes (fail-open is
239
+ by design; a dead reranker must not turn every recall into a WARNING
240
+ stream)."""
241
+ now = time.monotonic()
242
+ # Sentinel must be None, not 0.0: time.monotonic() is measured from an
243
+ # arbitrary origin (system boot on Linux), so a 0.0 default suppresses
244
+ # the FIRST warning entirely for the first 300s of uptime.
245
+ last = getattr(self, "_rerank_warn_at", None)
246
+ if last is None or now - last >= 300:
247
+ self._rerank_warn_at = now
248
+ self.logger.warning(
249
+ "recall rerank failed (fail-open to ANN order): %s", exc)
250
+ else:
251
+ self.logger.debug(
252
+ "recall rerank failed (fail-open to ANN order): %s", exc)
@@ -0,0 +1,17 @@
1
+ """Colony intelligence learning sub-package.
2
+
3
+ Provides:
4
+ - FeedbackStore — persist/retrieve user corrections
5
+ - ContinuousLearner — near-real-time signal ingestion and weight updates
6
+ """
7
+
8
+ from .feedback_store import FeedbackStore, UserCorrection
9
+ from .continuous_learner import ContinuousLearner, BriefingEngagement, GoalOutcome
10
+
11
+ __all__ = [
12
+ "FeedbackStore",
13
+ "UserCorrection",
14
+ "ContinuousLearner",
15
+ "BriefingEngagement",
16
+ "GoalOutcome",
17
+ ]