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,217 @@
1
+ """Metrics collection for cognitive performance tracking."""
2
+ from dataclasses import dataclass
3
+ from typing import Dict, List, Optional
4
+ from datetime import datetime, timedelta
5
+ import statistics
6
+
7
+
8
+ @dataclass
9
+ class MetricObservation:
10
+ """Single metric observation."""
11
+ metric_type: str
12
+ value: float
13
+ domain: str
14
+ recorded_at: datetime
15
+ context: Optional[dict] = None
16
+
17
+
18
+ class MetricsCollector:
19
+ """Collect and aggregate metrics for CPI computation."""
20
+
21
+ def __init__(self, graph: "ColonyGraph"):
22
+ self.graph = graph
23
+ self._buffer: List[MetricObservation] = []
24
+
25
+ async def record(
26
+ self,
27
+ metric_type: str,
28
+ value: float,
29
+ domain: str = "general",
30
+ context: Optional[dict] = None
31
+ ) -> None:
32
+ """Record a metric observation."""
33
+ observation = MetricObservation(
34
+ metric_type=metric_type,
35
+ value=value,
36
+ domain=domain,
37
+ recorded_at=datetime.now(),
38
+ context=context,
39
+ )
40
+
41
+ # Add to buffer
42
+ self._buffer.append(observation)
43
+
44
+ # Persist to graph
45
+ await self._persist(observation)
46
+
47
+ async def get_metrics(
48
+ self,
49
+ domain: str,
50
+ days: int = 7
51
+ ) -> Dict[str, float]:
52
+ """Get aggregated metrics for a domain."""
53
+ cutoff = datetime.now() - timedelta(days=days)
54
+
55
+ # Filter buffer
56
+ relevant = [
57
+ obs for obs in self._buffer
58
+ if obs.domain == domain and obs.recorded_at >= cutoff
59
+ ]
60
+
61
+ # Also fetch from graph
62
+ try:
63
+ graph_metrics = await self._fetch_from_graph(domain, days)
64
+ except (OSError, RuntimeError):
65
+ graph_metrics = []
66
+
67
+ # Combine
68
+ all_observations = relevant + graph_metrics
69
+
70
+ # Aggregate by type
71
+ by_type: Dict[str, List[float]] = {}
72
+ for obs in all_observations:
73
+ if obs.metric_type not in by_type:
74
+ by_type[obs.metric_type] = []
75
+ by_type[obs.metric_type].append(obs.value)
76
+
77
+ # Compute aggregates
78
+ result = {}
79
+ for metric_type, values in by_type.items():
80
+ if values:
81
+ result[metric_type] = statistics.mean(values)
82
+ result[f"{metric_type}_count"] = len(values)
83
+ if len(values) > 1:
84
+ result[f"{metric_type}_std"] = statistics.stdev(values)
85
+
86
+ return result
87
+
88
+ async def record_prediction(self, correct: bool, confidence: float) -> None:
89
+ """Record prediction outcome."""
90
+ await self.record("prediction_outcome", 1.0 if correct else 0.0, "prediction")
91
+ await self.record("prediction_confidence", confidence, "prediction")
92
+
93
+ async def record_tool_usage(
94
+ self,
95
+ tool_name: str,
96
+ success: bool,
97
+ latency_ms: float
98
+ ) -> None:
99
+ """Record tool usage metrics."""
100
+ await self.record(f"tool_{tool_name}_success", 1.0 if success else 0.0, "tool_efficiency")
101
+ await self.record(f"tool_{tool_name}_latency", latency_ms, "tool_efficiency")
102
+
103
+ async def record_memory_retrieval(
104
+ self,
105
+ relevance_score: float,
106
+ latency_ms: float
107
+ ) -> None:
108
+ """Record memory retrieval metrics."""
109
+ await self.record("relevance_score", relevance_score, "retrieval")
110
+ await self.record("retrieval_latency", latency_ms, "retrieval")
111
+
112
+ async def record_task_completion(
113
+ self,
114
+ task_type: str,
115
+ duration_minutes: float
116
+ ) -> None:
117
+ """Record task completion metrics."""
118
+ await self.record(f"task_{task_type}_duration", duration_minutes, "goal_progress")
119
+ await self.record(f"task_{task_type}_completed", 1.0, "goal_progress")
120
+
121
+ async def record_suggestion(
122
+ self,
123
+ suggestion_type: str,
124
+ accepted: bool
125
+ ) -> None:
126
+ """Record proactive suggestion outcome."""
127
+ await self.record(f"suggestion_{suggestion_type}", 1.0 if accepted else 0.0, "initiative")
128
+
129
+ async def record_response_quality(
130
+ self,
131
+ relevance: float,
132
+ conciseness: float,
133
+ actionability: float
134
+ ) -> None:
135
+ """Record response quality metrics."""
136
+ await self.record("relevance_score", relevance, "response_quality")
137
+ await self.record("conciseness_score", conciseness, "response_quality")
138
+ await self.record("actionability_score", actionability, "response_quality")
139
+
140
+ async def _persist(self, observation: MetricObservation) -> None:
141
+ """Persist observation to Neo4j."""
142
+ try:
143
+ person_id = (observation.context or {}).get("person_id")
144
+ async with self.graph.driver.session(database=self.graph.database) as session:
145
+ if person_id:
146
+ await session.run("""
147
+ CREATE (m:CognitiveMetric {
148
+ id: randomUUID(),
149
+ metric_type: $metric_type,
150
+ value: $value,
151
+ domain: $domain,
152
+ recorded_at: datetime($timestamp),
153
+ context: $context
154
+ })
155
+ WITH m
156
+ MERGE (p:Person {id: $person_id})
157
+ CREATE (m)-[:OBSERVED_FOR]->(p)
158
+ """,
159
+ metric_type=observation.metric_type,
160
+ value=observation.value,
161
+ domain=observation.domain,
162
+ timestamp=observation.recorded_at.isoformat(),
163
+ context=observation.context or {},
164
+ person_id=person_id,
165
+ )
166
+ else:
167
+ await session.run("""
168
+ CREATE (m:CognitiveMetric {
169
+ id: randomUUID(),
170
+ metric_type: $metric_type,
171
+ value: $value,
172
+ domain: $domain,
173
+ recorded_at: datetime($timestamp),
174
+ context: $context
175
+ })
176
+ """,
177
+ metric_type=observation.metric_type,
178
+ value=observation.value,
179
+ domain=observation.domain,
180
+ timestamp=observation.recorded_at.isoformat(),
181
+ context=observation.context or {},
182
+ )
183
+ except (OSError, RuntimeError):
184
+ pass # Don't fail if persistence fails
185
+
186
+ async def _fetch_from_graph(
187
+ self,
188
+ domain: str,
189
+ days: int
190
+ ) -> List[MetricObservation]:
191
+ """Fetch metrics from Neo4j."""
192
+ try:
193
+ async with self.graph.driver.session(database=self.graph.database) as session:
194
+ result = await session.run("""
195
+ MATCH (m:CognitiveMetric)
196
+ WHERE m.domain = $domain
197
+ AND m.recorded_at >= datetime() - duration({days: $days})
198
+ RETURN m.metric_type AS type, m.value AS value, m.recorded_at AS ts
199
+ """, domain=domain, days=days)
200
+
201
+ observations = []
202
+ async for record in result:
203
+ observations.append(MetricObservation(
204
+ metric_type=record["type"],
205
+ value=record["value"],
206
+ domain=domain,
207
+ recorded_at=record["ts"],
208
+ ))
209
+ return observations
210
+ except (OSError, RuntimeError):
211
+ return []
212
+
213
+ def flush_buffer(self) -> int:
214
+ """Clear in-memory buffer, return count of flushed items."""
215
+ count = len(self._buffer)
216
+ self._buffer.clear()
217
+ return count
@@ -0,0 +1,299 @@
1
+ """Deprecated legacy CPI detector.
2
+
3
+ The canonical performance surface is ``SelfhoodBenchmark``. This module is
4
+ kept only to emit gap proposals during migration; it no longer invents
5
+ flattering values when evidence is absent and it never authorizes a write.
6
+ """
7
+ import logging
8
+ from dataclasses import dataclass, field
9
+ from typing import Dict, List, Optional
10
+ from datetime import datetime
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ @dataclass
16
+ class CPIComponent:
17
+ """Score for a single CPI dimension."""
18
+ name: str
19
+ score: float # 0-100
20
+ trend: str = "stable" # "improving", "declining", "stable"
21
+ metrics: Dict[str, float] = field(default_factory=dict)
22
+ available: bool = True
23
+
24
+
25
+ @dataclass
26
+ class CognitivePerformanceIndex:
27
+ """Deprecated compatibility shape; use SelfhoodBenchmark rollups."""
28
+ retrieval: CPIComponent
29
+ prediction: CPIComponent
30
+ goal_progress: CPIComponent
31
+ tool_efficiency: CPIComponent
32
+ initiative: CPIComponent
33
+ response_quality: CPIComponent
34
+ overall: float
35
+ computed_at: datetime
36
+ deprecated: bool = True
37
+ available_components: List[str] = field(default_factory=list)
38
+
39
+
40
+ class PerformanceIndexComputer:
41
+ """Compute 6-component Cognitive Performance Index."""
42
+
43
+ COMPONENT_WEIGHTS = {
44
+ "retrieval": 0.20,
45
+ "prediction": 0.15,
46
+ "goal_progress": 0.20,
47
+ "tool_efficiency": 0.15,
48
+ "initiative": 0.15,
49
+ "response_quality": 0.15,
50
+ }
51
+
52
+ # Thresholds for trend detection
53
+ IMPROVEMENT_THRESHOLD = 5.0 # 5-point improvement
54
+ DECLINE_THRESHOLD = -5.0
55
+
56
+ def __init__(self, graph: "ColonyGraph"):
57
+ self.graph = graph
58
+ self._prior_scores: dict[str, list[float]] = {} # component → recent scores
59
+
60
+ async def compute(self, metrics_collector: Optional["MetricsCollector"] = None) -> CognitivePerformanceIndex:
61
+ """Compute CPI from recent metrics."""
62
+ components = {}
63
+
64
+ # 1. Retrieval: memory quality, relevance, latency
65
+ retrieval_metrics = await self._get_metrics(metrics_collector, "retrieval", days=7)
66
+ components["retrieval"] = self._compute_retrieval(retrieval_metrics)
67
+
68
+ # 2. Prediction: accuracy, confidence calibration
69
+ pred_metrics = await self._get_metrics(metrics_collector, "prediction", days=7)
70
+ components["prediction"] = self._compute_prediction(pred_metrics)
71
+
72
+ # 3. Goal Progress: task completion velocity
73
+ goal_metrics = await self._get_metrics(metrics_collector, "goal_progress", days=7)
74
+ components["goal_progress"] = self._compute_goal_progress(goal_metrics)
75
+
76
+ # 4. Tool Efficiency: success rate, latency
77
+ tool_metrics = await self._get_metrics(metrics_collector, "tool_efficiency", days=7)
78
+ components["tool_efficiency"] = self._compute_tool_efficiency(tool_metrics)
79
+
80
+ # 5. Initiative: proactive suggestion hit rate
81
+ init_metrics = await self._get_metrics(metrics_collector, "initiative", days=7)
82
+ components["initiative"] = self._compute_initiative(init_metrics)
83
+
84
+ # 6. Response Quality: relevance, conciseness, actionability
85
+ quality_metrics = await self._get_metrics(metrics_collector, "response_quality", days=7)
86
+ components["response_quality"] = self._compute_response_quality(quality_metrics)
87
+
88
+ # Reweight only evidence-bearing dimensions. Missing dimensions are
89
+ # unavailable, not neutral, successful, or silently zero evidence.
90
+ available_weight = sum(
91
+ weight for name, weight in self.COMPONENT_WEIGHTS.items()
92
+ if components[name].available)
93
+ overall = (sum(
94
+ components[name].score * weight
95
+ for name, weight in self.COMPONENT_WEIGHTS.items()
96
+ if components[name].available
97
+ ) / available_weight) if available_weight else 0.0
98
+ available = [name for name, component in components.items()
99
+ if component.available]
100
+
101
+ return CognitivePerformanceIndex(
102
+ retrieval=components["retrieval"],
103
+ prediction=components["prediction"],
104
+ goal_progress=components["goal_progress"],
105
+ tool_efficiency=components["tool_efficiency"],
106
+ initiative=components["initiative"],
107
+ response_quality=components["response_quality"],
108
+ overall=overall,
109
+ computed_at=datetime.now(),
110
+ deprecated=True,
111
+ available_components=available,
112
+ )
113
+
114
+ @staticmethod
115
+ def _unavailable(name: str) -> CPIComponent:
116
+ return CPIComponent(
117
+ name=name, score=0.0, trend="unavailable",
118
+ metrics={"available": False, "deprecated": True},
119
+ available=False)
120
+
121
+ async def _get_metrics(
122
+ self,
123
+ collector: Optional["MetricsCollector"],
124
+ domain: str,
125
+ days: int = 7
126
+ ) -> Dict[str, float]:
127
+ """Fetch metrics for a domain."""
128
+ if collector:
129
+ try:
130
+ return await collector.get_metrics(domain, days=days)
131
+ except Exception as exc:
132
+ logger.debug("Collector metrics failed for %s: %s", domain, exc)
133
+
134
+ # Fallback: query graph directly
135
+ try:
136
+ async with self.graph.driver.session(database=self.graph.database) as session:
137
+ result = await session.run("""
138
+ MATCH (m:CognitiveMetric)
139
+ WHERE m.domain = $domain
140
+ AND m.recorded_at >= datetime() - duration({days: $days})
141
+ RETURN m.metric_type AS type, m.value AS value
142
+ """, domain=domain, days=days)
143
+
144
+ metrics = {}
145
+ async for record in result:
146
+ metrics[record["type"]] = record["value"]
147
+ return metrics
148
+ except Exception as exc:
149
+ logger.debug("Graph metrics query failed for %s: %s", domain, exc)
150
+ return {}
151
+
152
+ def _compute_retrieval(self, metrics: Dict[str, float]) -> CPIComponent:
153
+ """Compute retrieval component score."""
154
+ if "relevance_score" not in metrics or "latency_ms" not in metrics:
155
+ return self._unavailable("retrieval")
156
+ relevance = metrics["relevance_score"]
157
+ latency = metrics["latency_ms"]
158
+
159
+ # Latency penalty (cap at 2s)
160
+ latency_score = max(0, 100 - (latency / 20))
161
+
162
+ score = (relevance * 0.7 + latency_score * 0.3)
163
+ trend = self._compute_trend("retrieval", score)
164
+
165
+ return CPIComponent(
166
+ name="retrieval",
167
+ score=score,
168
+ trend=trend,
169
+ metrics=metrics,
170
+ )
171
+
172
+ def _compute_prediction(self, metrics: Dict[str, float]) -> CPIComponent:
173
+ """Compute prediction component score."""
174
+ correct = metrics.get("correct_count", 0)
175
+ total = metrics.get("total_predictions", 0)
176
+ if total <= 0:
177
+ return self._unavailable("prediction")
178
+
179
+ accuracy = (correct / max(total, 1)) * 100
180
+ trend = self._compute_trend("prediction", accuracy)
181
+
182
+ return CPIComponent(
183
+ name="prediction",
184
+ score=accuracy,
185
+ trend=trend,
186
+ metrics={"accuracy": accuracy, "total": total},
187
+ )
188
+
189
+ def _compute_goal_progress(self, metrics: Dict[str, float]) -> CPIComponent:
190
+ """Compute goal progress component score."""
191
+ completed = metrics.get("completed_tasks", 0)
192
+ total = metrics.get("total_tasks", 0)
193
+ if total <= 0 or "velocity" not in metrics:
194
+ return self._unavailable("goal_progress")
195
+ velocity = metrics["velocity"]
196
+
197
+ completion_rate = (completed / max(total, 1)) * 100
198
+ velocity_score = min(velocity * 20, 100) # 5 tasks/day = 100
199
+
200
+ score = completion_rate * 0.6 + velocity_score * 0.4
201
+ trend = self._compute_trend("goal_progress", score)
202
+
203
+ return CPIComponent(
204
+ name="goal_progress",
205
+ score=score,
206
+ trend=trend,
207
+ metrics=metrics,
208
+ )
209
+
210
+ def _compute_tool_efficiency(self, metrics: Dict[str, float]) -> CPIComponent:
211
+ """Compute tool efficiency component score."""
212
+ if "success_rate" not in metrics or "avg_latency_ms" not in metrics:
213
+ return self._unavailable("tool_efficiency")
214
+ success_rate = metrics["success_rate"]
215
+ avg_latency = metrics["avg_latency_ms"]
216
+
217
+ latency_score = max(0, 100 - (avg_latency / 50))
218
+ score = success_rate * 0.7 + latency_score * 0.3
219
+ trend = self._compute_trend("tool_efficiency", score)
220
+
221
+ return CPIComponent(
222
+ name="tool_efficiency",
223
+ score=score,
224
+ trend=trend,
225
+ metrics=metrics,
226
+ )
227
+
228
+ def _compute_initiative(self, metrics: Dict[str, float]) -> CPIComponent:
229
+ """Compute initiative component score."""
230
+ suggestions = metrics.get("suggestions_made", 0)
231
+ accepted = metrics.get("suggestions_accepted", 0)
232
+
233
+ if suggestions <= 0:
234
+ return self._unavailable("initiative")
235
+ hit_rate = (accepted / suggestions) * 100
236
+
237
+ volume_score = min(suggestions * 10, 100) # 10 suggestions = 100
238
+
239
+ score = hit_rate * 0.7 + volume_score * 0.3
240
+ trend = self._compute_trend("initiative", score)
241
+
242
+ return CPIComponent(
243
+ name="initiative",
244
+ score=score,
245
+ trend=trend,
246
+ metrics=metrics,
247
+ )
248
+
249
+ def _compute_response_quality(self, metrics: Dict[str, float]) -> CPIComponent:
250
+ """Compute response quality component score."""
251
+ required = {"relevance_score", "conciseness_score",
252
+ "actionability_score"}
253
+ if not required <= set(metrics):
254
+ return self._unavailable("response_quality")
255
+ relevance = metrics["relevance_score"]
256
+ conciseness = metrics["conciseness_score"]
257
+ actionability = metrics["actionability_score"]
258
+
259
+ score = relevance * 0.4 + conciseness * 0.3 + actionability * 0.3
260
+ trend = self._compute_trend("response_quality", score)
261
+
262
+ return CPIComponent(
263
+ name="response_quality",
264
+ score=score,
265
+ trend=trend,
266
+ metrics=metrics,
267
+ )
268
+
269
+ def _compute_trend(self, component: str, current_score: float) -> str:
270
+ """Determine trend by comparing to the rolling average of prior scores.
271
+
272
+ Uses an in-session cache of up to 5 recent scores per component.
273
+ On first call the cache is empty, so "stable" is returned.
274
+
275
+ Returns:
276
+ "improving" — current score is ≥ IMPROVEMENT_THRESHOLD above prior avg
277
+ "declining" — current score is ≤ DECLINE_THRESHOLD below prior avg
278
+ "stable" — within threshold range, or no prior data
279
+ """
280
+ prior = self._prior_scores.get(component, [])
281
+
282
+ if not prior:
283
+ # No prior data — record current score and report stable
284
+ self._prior_scores[component] = [current_score]
285
+ return "stable"
286
+
287
+ prior_avg = sum(prior) / len(prior)
288
+ delta = current_score - prior_avg
289
+
290
+ if delta >= self.IMPROVEMENT_THRESHOLD:
291
+ trend = "improving"
292
+ elif delta <= self.DECLINE_THRESHOLD:
293
+ trend = "declining"
294
+ else:
295
+ trend = "stable"
296
+
297
+ # Keep a rolling window of up to 5 prior scores
298
+ self._prior_scores[component] = ([current_score] + prior)[:5]
299
+ return trend