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,320 @@
1
+ """Task Planner — break complex requests into subtasks.
2
+
3
+ Capabilities:
4
+ - Dependency detection
5
+ - Parallel task identification
6
+ - Resource estimation
7
+ """
8
+
9
+ import re
10
+ from dataclasses import dataclass, field
11
+ from datetime import datetime
12
+ from enum import Enum
13
+ from typing import Any, Dict, List, Optional, Set
14
+
15
+ import logging
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+ # Patterns for identifying independently-executable task types
20
+ _INDEPENDENT_TASK_PATTERNS = [
21
+ re.compile(r'\b(research|look up|find out|search for)\b'),
22
+ re.compile(r'\b(write|draft|compose|create)\b'),
23
+ re.compile(r'\b(schedule|book|reserve|arrange)\b'),
24
+ re.compile(r'\b(notify|email|message|send)\b'),
25
+ re.compile(r'\b(download|fetch|retrieve)\b'),
26
+ ]
27
+
28
+ # Patterns indicating an explicit sequential dependency between tasks
29
+ _DEPENDENCY_PATTERNS = [
30
+ re.compile(r'\b(then|after|once|following|based on|using the|with the)\b'),
31
+ ]
32
+
33
+ # Keywords indicating sequential ordering (creates dependencies)
34
+ _SEQUENTIAL_PATTERN = re.compile(
35
+ r"\s+(?:then|next|finally|after that|subsequently|afterward|before)\s+",
36
+ re.IGNORECASE,
37
+ )
38
+
39
+ # Keywords indicating parallel tasks (no dependencies)
40
+ _PARALLEL_PATTERN = re.compile(
41
+ r"\s+(?:and also|also|simultaneously|at the same time|in parallel)\s+",
42
+ re.IGNORECASE,
43
+ )
44
+
45
+ # Keywords that suggest higher effort
46
+ _HIGH_EFFORT_WORDS = frozenset(
47
+ {"research", "analyze", "analyse", "comprehensive", "detailed",
48
+ "thorough", "complex", "deep", "investigate", "audit"}
49
+ )
50
+
51
+ # Keywords that suggest lower effort
52
+ _LOW_EFFORT_WORDS = frozenset(
53
+ {"quick", "simple", "brief", "short", "fast", "small", "minor",
54
+ "trivial", "basic", "easy"}
55
+ )
56
+
57
+ # Keywords that elevate priority
58
+ _CRITICAL_WORDS = frozenset(
59
+ {"critical", "urgent", "immediately", "asap", "emergency", "blocker"}
60
+ )
61
+
62
+ _HIGH_PRIO_WORDS = frozenset(
63
+ {"important", "priority", "soon", "required", "must"}
64
+ )
65
+
66
+
67
+ class TaskPriority(str, Enum):
68
+ """Priority levels for subtasks."""
69
+
70
+ CRITICAL = "critical"
71
+ HIGH = "high"
72
+ MEDIUM = "medium"
73
+ LOW = "low"
74
+
75
+
76
+ @dataclass
77
+ class SubTask:
78
+ """A subtask in a decomposition.
79
+
80
+ Attributes:
81
+ id: Unique subtask identifier
82
+ description: Human-readable description
83
+ priority: Execution priority
84
+ dependencies: IDs of subtasks that must complete first
85
+ estimated_effort: Relative effort units (1.0 = baseline)
86
+ assigned_to: Optional node ID for mesh distribution
87
+ """
88
+
89
+ id: str
90
+ description: str
91
+ priority: TaskPriority = TaskPriority.MEDIUM
92
+ dependencies: List[str] = field(default_factory=list)
93
+ estimated_effort: float = 1.0
94
+ assigned_to: Optional[str] = None
95
+
96
+
97
+ @dataclass
98
+ class TaskPlan:
99
+ """A complete task decomposition.
100
+
101
+ Attributes:
102
+ id: Unique plan identifier
103
+ description: The original request
104
+ subtasks: Ordered list of subtasks
105
+ parallel_groups: Groups of subtask IDs that can execute concurrently
106
+ total_effort: Sum of all subtask efforts
107
+ """
108
+
109
+ id: str
110
+ description: str
111
+ subtasks: List[SubTask] = field(default_factory=list)
112
+ parallel_groups: List[List[str]] = field(default_factory=list)
113
+ total_effort: float = 0.0
114
+
115
+
116
+ class TaskPlanner:
117
+ """Decompose complex requests into executable plans.
118
+
119
+ Takes a natural-language request, breaks it into subtasks,
120
+ identifies dependencies, and groups parallelizable work.
121
+
122
+ Decomposition rules:
123
+ - Sequential keywords ("then", "next", "finally"…) create ordered dependencies.
124
+ - Parallel keywords ("and also", "simultaneously"…) create independent tasks.
125
+ - Plain "and" splits into parallel tasks when no sequential markers are present.
126
+ - A single-sentence request creates one subtask.
127
+
128
+ Args:
129
+ graph_client: Colony graph client for context retrieval
130
+ """
131
+
132
+ def __init__(self, graph_client: Any) -> None:
133
+ self.graph = graph_client
134
+
135
+ async def plan(self, request: str, context: Optional[Dict[str, Any]] = None) -> TaskPlan:
136
+ """Create execution plan for a request.
137
+
138
+ Args:
139
+ request: Natural-language task description
140
+ context: Optional context for better decomposition
141
+
142
+ Returns:
143
+ TaskPlan with subtasks and parallel groups
144
+ """
145
+ subtasks = await self._decompose(request)
146
+
147
+ await self._identify_dependencies(subtasks)
148
+
149
+ parallel_groups = self._find_parallel_groups(subtasks)
150
+
151
+ total_effort = sum(s.estimated_effort for s in subtasks)
152
+
153
+ plan = TaskPlan(
154
+ id=f"plan-{hash(request) % 10000:04d}",
155
+ description=request,
156
+ subtasks=subtasks,
157
+ parallel_groups=parallel_groups,
158
+ total_effort=total_effort,
159
+ )
160
+
161
+ logger.debug(
162
+ "Created plan %s: %d subtasks, %d parallel groups, effort=%.1f",
163
+ plan.id,
164
+ len(subtasks),
165
+ len(parallel_groups),
166
+ total_effort,
167
+ )
168
+ return plan
169
+
170
+ async def _decompose(self, request: str) -> List[SubTask]:
171
+ """Decompose request into subtasks using keyword rules.
172
+
173
+ Sequential markers create ordered dependencies; parallel markers
174
+ and plain conjunctions create independent groups.
175
+ """
176
+ # Check for sequential ordering markers first
177
+ seq_parts = _SEQUENTIAL_PATTERN.split(request)
178
+ if len(seq_parts) > 1:
179
+ return self._build_subtasks(seq_parts, sequential=True)
180
+
181
+ # Check for explicit parallel markers
182
+ par_parts = _PARALLEL_PATTERN.split(request)
183
+ if len(par_parts) > 1:
184
+ return self._build_subtasks(par_parts, sequential=False)
185
+
186
+ # Fall back to splitting on plain "and" (parallel by default)
187
+ and_parts = re.split(r"\s+and\s+", request, flags=re.IGNORECASE)
188
+ if len(and_parts) > 1:
189
+ return self._build_subtasks(and_parts, sequential=False)
190
+
191
+ # Single task
192
+ return [self._make_subtask("subtask-1", request.strip() or request)]
193
+
194
+ def _build_subtasks(self, parts: List[str], *, sequential: bool) -> List[SubTask]:
195
+ """Build subtask list from text parts.
196
+
197
+ Args:
198
+ parts: Text fragments representing individual tasks
199
+ sequential: If True, each task depends on the previous one
200
+ """
201
+ subtasks: List[SubTask] = []
202
+ for i, part in enumerate(parts):
203
+ part = part.strip()
204
+ if not part:
205
+ continue
206
+ st = self._make_subtask(f"subtask-{len(subtasks) + 1}", part)
207
+ if sequential and subtasks:
208
+ st.dependencies.append(subtasks[-1].id)
209
+ subtasks.append(st)
210
+ return subtasks or [self._make_subtask("subtask-1", "Analyse request")]
211
+
212
+ def _make_subtask(self, task_id: str, description: str) -> SubTask:
213
+ """Construct a SubTask, inferring priority and effort from keywords."""
214
+ lower = description.lower()
215
+
216
+ # Priority
217
+ if any(w in lower for w in _CRITICAL_WORDS):
218
+ priority = TaskPriority.CRITICAL
219
+ elif any(w in lower for w in _HIGH_PRIO_WORDS):
220
+ priority = TaskPriority.HIGH
221
+ else:
222
+ priority = TaskPriority.MEDIUM
223
+
224
+ # Effort
225
+ if any(w in lower for w in _HIGH_EFFORT_WORDS):
226
+ effort = 2.0
227
+ elif any(w in lower for w in _LOW_EFFORT_WORDS):
228
+ effort = 0.5
229
+ else:
230
+ effort = 1.0
231
+
232
+ return SubTask(
233
+ id=task_id,
234
+ description=description,
235
+ priority=priority,
236
+ estimated_effort=effort,
237
+ )
238
+
239
+ async def _identify_dependencies(self, subtasks: List[SubTask]) -> None:
240
+ """Heuristic dependency analysis between subtasks.
241
+
242
+ ``_decompose`` creates a linear dependency chain by default.
243
+ This method clears dependencies between pairs of tasks whose
244
+ descriptions suggest they are genuinely independent — i.e. no
245
+ explicit ordering language and both match independence patterns.
246
+
247
+ Sequential tasks already have dependencies set by ``_decompose``.
248
+ An LLM-assisted Phase 2 can be wired in future when a router is
249
+ available.
250
+ """
251
+ if len(subtasks) < 2:
252
+ return
253
+
254
+ for i, task in enumerate(subtasks):
255
+ if i == 0:
256
+ continue
257
+
258
+ desc_lower = task.description.lower()
259
+ has_explicit_dep = any(p.search(desc_lower) for p in _DEPENDENCY_PATTERNS)
260
+ if has_explicit_dep:
261
+ continue # Keep the sequential dependency
262
+
263
+ is_independent_type = any(p.search(desc_lower) for p in _INDEPENDENT_TASK_PATTERNS)
264
+ if not is_independent_type:
265
+ continue
266
+
267
+ prev = subtasks[i - 1]
268
+ prev_lower = prev.description.lower()
269
+ prev_is_independent = any(p.search(prev_lower) for p in _INDEPENDENT_TASK_PATTERNS)
270
+ if prev_is_independent:
271
+ # Both tasks are independently typed — allow parallel execution
272
+ task.dependencies = [
273
+ d for d in task.dependencies if d != prev.id
274
+ ]
275
+ logger.debug(
276
+ "TaskPlanner: cleared dependency %s → %s "
277
+ "(both tasks appear independent)",
278
+ prev.id,
279
+ task.id,
280
+ )
281
+
282
+ def _find_parallel_groups(self, subtasks: List[SubTask]) -> List[List[str]]:
283
+ """Find subtasks that can run in parallel using topological levels.
284
+
285
+ Performs a level-order topological sort: tasks at level 0 have no
286
+ dependencies, tasks at level 1 depend only on level-0 tasks, etc.
287
+ Tasks within the same level can execute concurrently.
288
+
289
+ Args:
290
+ subtasks: All subtasks in the plan
291
+
292
+ Returns:
293
+ List of groups (each group is a list of subtask IDs that can
294
+ run concurrently).
295
+ """
296
+ if not subtasks:
297
+ return []
298
+
299
+ remaining: Dict[str, SubTask] = {s.id: s for s in subtasks}
300
+ completed: Set[str] = set()
301
+ groups: List[List[str]] = []
302
+
303
+ while remaining:
304
+ ready = [
305
+ sid
306
+ for sid, s in remaining.items()
307
+ if all(dep in completed for dep in s.dependencies)
308
+ ]
309
+
310
+ if not ready:
311
+ # Cycle or unresolvable — dump remainder into one group
312
+ groups.append(list(remaining.keys()))
313
+ break
314
+
315
+ groups.append(ready)
316
+ for sid in ready:
317
+ completed.add(sid)
318
+ del remaining[sid]
319
+
320
+ return groups
@@ -0,0 +1,217 @@
1
+ """Tool Learner — learn user's preferred tools for different tasks.
2
+
3
+ Tracks:
4
+ - Which tools are used for which task types
5
+ - Success rates per tool
6
+ - User satisfaction signals (explicit + implicit)
7
+ """
8
+
9
+ from dataclasses import dataclass, field
10
+ from datetime import datetime
11
+ from typing import Any, Dict, List, Optional, Tuple
12
+
13
+ import logging
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @dataclass
19
+ class ToolUsage:
20
+ """Record of a tool being used for a task.
21
+
22
+ Attributes:
23
+ tool_name: Name of the tool used
24
+ task_type: Category of task the tool was applied to
25
+ success: Whether the tool usage succeeded
26
+ user_feedback: Optional explicit feedback ("helpful", "not_helpful", None)
27
+ timestamp: When the usage occurred
28
+ """
29
+
30
+ tool_name: str
31
+ task_type: str
32
+ success: bool
33
+ user_feedback: Optional[str] = None
34
+ timestamp: datetime = field(default_factory=datetime.now)
35
+
36
+
37
+ @dataclass
38
+ class ToolPreference:
39
+ """Learned preference for a tool on a task type.
40
+
41
+ Attributes:
42
+ tool_name: Name of the preferred tool
43
+ task_type: Task category this preference applies to
44
+ success_rate: Running success rate (0-1)
45
+ usage_count: Total number of times this tool was used for this task type
46
+ last_used: Most recent usage timestamp
47
+ user_rating: Recency-weighted user satisfaction score (0-1)
48
+ """
49
+
50
+ tool_name: str
51
+ task_type: str
52
+ success_rate: float
53
+ usage_count: int
54
+ last_used: datetime
55
+ user_rating: float
56
+
57
+
58
+ class ToolLearner:
59
+ """Learn and apply tool preferences from usage patterns.
60
+
61
+ Maintains in-memory preference records per task type, updated on
62
+ each recorded usage. Preferred tool selection blends success rate
63
+ (60%) with user rating (40%).
64
+
65
+ Args:
66
+ graph_client: Colony graph client for persistent storage
67
+ """
68
+
69
+ def __init__(self, graph_client: Any) -> None:
70
+ self.graph = graph_client
71
+ self._preferences: Dict[str, List[ToolPreference]] = {}
72
+
73
+ async def record_usage(self, usage: ToolUsage) -> None:
74
+ """Record a tool usage event and update preferences.
75
+
76
+ Args:
77
+ usage: The tool usage to record
78
+ """
79
+ key = usage.task_type
80
+ if key not in self._preferences:
81
+ self._preferences[key] = []
82
+
83
+ # Find or create preference record
84
+ pref = next(
85
+ (p for p in self._preferences[key] if p.tool_name == usage.tool_name),
86
+ None,
87
+ )
88
+
89
+ if pref:
90
+ old_count = pref.usage_count
91
+ pref.usage_count += 1
92
+ pref.success_rate = (
93
+ (pref.success_rate * old_count + (1.0 if usage.success else 0.0))
94
+ / pref.usage_count
95
+ )
96
+ pref.last_used = usage.timestamp
97
+ else:
98
+ self._preferences[key].append(
99
+ ToolPreference(
100
+ tool_name=usage.tool_name,
101
+ task_type=usage.task_type,
102
+ success_rate=1.0 if usage.success else 0.0,
103
+ usage_count=1,
104
+ last_used=usage.timestamp,
105
+ user_rating=0.5,
106
+ )
107
+ )
108
+
109
+ logger.debug(
110
+ "Recorded tool usage: %s for %s (success=%s)",
111
+ usage.tool_name,
112
+ usage.task_type,
113
+ usage.success,
114
+ )
115
+
116
+ async def get_preferred_tool(self, task_type: str) -> Optional[str]:
117
+ """Get the preferred tool for a task type.
118
+
119
+ Selection blends success rate (60%) with user rating (40%).
120
+
121
+ Args:
122
+ task_type: The task category to find a tool for
123
+
124
+ Returns:
125
+ Tool name or None if no preferences exist
126
+ """
127
+ if task_type not in self._preferences:
128
+ return None
129
+
130
+ prefs = self._preferences[task_type]
131
+ if not prefs:
132
+ return None
133
+
134
+ sorted_prefs = sorted(
135
+ prefs,
136
+ key=lambda p: (p.success_rate * 0.6 + p.user_rating * 0.4),
137
+ reverse=True,
138
+ )
139
+
140
+ return sorted_prefs[0].tool_name
141
+
142
+ async def get_all_preferences(self, task_type: str) -> List[ToolPreference]:
143
+ """Get all tool preferences for a task type, sorted by score.
144
+
145
+ Args:
146
+ task_type: The task category to query
147
+
148
+ Returns:
149
+ Sorted list of preferences (best first)
150
+ """
151
+ prefs = self._preferences.get(task_type, [])
152
+ return sorted(
153
+ prefs,
154
+ key=lambda p: (p.success_rate * 0.6 + p.user_rating * 0.4),
155
+ reverse=True,
156
+ )
157
+
158
+ async def update_user_rating(
159
+ self,
160
+ tool_name: str,
161
+ task_type: str,
162
+ rating: float,
163
+ ) -> None:
164
+ """Update the user satisfaction rating for a tool on a task type.
165
+
166
+ Uses an exponential moving average (alpha=0.3) so recent feedback
167
+ is weighted more heavily without fully discarding history.
168
+
169
+ Args:
170
+ tool_name: Name of the tool to rate
171
+ task_type: Task category this rating applies to
172
+ rating: New rating value (0-1)
173
+ """
174
+ rating = max(0.0, min(1.0, rating))
175
+ prefs = self._preferences.get(task_type, [])
176
+ pref = next((p for p in prefs if p.tool_name == tool_name), None)
177
+ if pref is None:
178
+ logger.warning("No preference record for %s on %s", tool_name, task_type)
179
+ return
180
+ alpha = 0.3
181
+ pref.user_rating = alpha * rating + (1 - alpha) * pref.user_rating
182
+ logger.debug(
183
+ "Updated user rating for %s on %s: %.2f",
184
+ tool_name,
185
+ task_type,
186
+ pref.user_rating,
187
+ )
188
+
189
+ async def get_usage_stats(self, task_type: str) -> Dict[str, Any]:
190
+ """Return summary statistics for all tools used on a task type.
191
+
192
+ Args:
193
+ task_type: The task category to summarise
194
+
195
+ Returns:
196
+ Dict with 'total_tools', 'total_usages', 'best_tool', and per-tool stats.
197
+ """
198
+ prefs = self._preferences.get(task_type, [])
199
+ if not prefs:
200
+ return {"total_tools": 0, "total_usages": 0, "best_tool": None, "tools": []}
201
+
202
+ best = await self.get_preferred_tool(task_type)
203
+ return {
204
+ "total_tools": len(prefs),
205
+ "total_usages": sum(p.usage_count for p in prefs),
206
+ "best_tool": best,
207
+ "tools": [
208
+ {
209
+ "name": p.tool_name,
210
+ "usage_count": p.usage_count,
211
+ "success_rate": p.success_rate,
212
+ "user_rating": p.user_rating,
213
+ "score": p.success_rate * 0.6 + p.user_rating * 0.4,
214
+ }
215
+ for p in prefs
216
+ ],
217
+ }
@@ -0,0 +1,79 @@
1
+ """Colony Graph Memory System.
2
+
3
+ Public API:
4
+ - ``ColonyGraph`` — async Neo4j client for memory storage & recall
5
+ - ``GraphConfig`` — connection settings dataclass
6
+ - ``run_migrations`` — idempotent schema setup
7
+ - Schema types (``Owner``, ``Person``, ``Memory``, ``Entity``, etc.)
8
+ - ``EdgeType`` / ``TrustTier`` enums
9
+ - Cypher query constants in ``queries``
10
+ """
11
+
12
+ from .client import ColonyGraph, GraphConfig
13
+ from .migrations import run_migrations, SCHEMA_V1
14
+ from .queries import (
15
+ COMPUTE_RELATIONSHIP_SCORES,
16
+ DECAY_ALL,
17
+ ENSURE_OWNER,
18
+ FIND_NEGLECTED_RELATIONSHIPS,
19
+ FIND_SHARED_ENTITIES,
20
+ GET_PERSON_WITH_SIGNALS,
21
+ LINK_PERSON_TO_OWNER,
22
+ PRUNE_WEAK_MEMORIES,
23
+ RECALL_BY_ENTITY,
24
+ RECALL_BY_TYPE,
25
+ RECORD_SCORE_CHANGE,
26
+ STORE_MEMORY,
27
+ STORE_SIGNAL,
28
+ TOUCH_MEMORY,
29
+ TRAVERSE_MEMORY_CONNECTIONS,
30
+ )
31
+ from .schema import (
32
+ Context,
33
+ EdgeType,
34
+ Entity,
35
+ Memory,
36
+ Owner,
37
+ Person,
38
+ Prediction,
39
+ ScoreEvent,
40
+ Signal,
41
+ TrustTier,
42
+ )
43
+
44
+ __all__ = [
45
+ # Client
46
+ "ColonyGraph",
47
+ "GraphConfig",
48
+ # Migrations
49
+ "run_migrations",
50
+ "SCHEMA_V1",
51
+ # Schema — nodes
52
+ "Owner",
53
+ "Person",
54
+ "Memory",
55
+ "Entity",
56
+ "Signal",
57
+ "Context",
58
+ "ScoreEvent",
59
+ "Prediction",
60
+ # Schema — enums
61
+ "EdgeType",
62
+ "TrustTier",
63
+ # Query constants
64
+ "STORE_MEMORY",
65
+ "RECALL_BY_ENTITY",
66
+ "RECALL_BY_TYPE",
67
+ "DECAY_ALL",
68
+ "PRUNE_WEAK_MEMORIES",
69
+ "TOUCH_MEMORY",
70
+ "GET_PERSON_WITH_SIGNALS",
71
+ "STORE_SIGNAL",
72
+ "COMPUTE_RELATIONSHIP_SCORES",
73
+ "RECORD_SCORE_CHANGE",
74
+ "FIND_NEGLECTED_RELATIONSHIPS",
75
+ "TRAVERSE_MEMORY_CONNECTIONS",
76
+ "FIND_SHARED_ENTITIES",
77
+ "ENSURE_OWNER",
78
+ "LINK_PERSON_TO_OWNER",
79
+ ]