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,55 @@
1
+ """Prospective runtime observations for the existing working-judgment queue.
2
+
3
+ Called only after the server rereads an owned native task. No model report,
4
+ tool result prose, caller-supplied outcome or imported history is evidence here.
5
+ """
6
+ from contextlib import closing
7
+ from datetime import datetime, timezone
8
+ import hashlib
9
+ import json
10
+ import math
11
+
12
+ VERSION = 'native-runtime-observation-v1'
13
+
14
+
15
+ def retain_outcome(review, native, state, owner):
16
+ binding = review.get('native_work') or {}
17
+ selection = binding.get('outcome_learning') or {}
18
+ observed = state.get('runtime_observation')
19
+ if selection.get('version') != VERSION or not observed:
20
+ return
21
+ started, ended = observed['started_at'], observed['ended_at']
22
+ if not all(type(value) in (int, float) and math.isfinite(value) for value in (started, ended)):
23
+ return
24
+ # Native run timestamps have whole-second precision. The binding marker
25
+ # is only set while this newly bound task has no runs.
26
+ if ended < started or started < math.floor(datetime.fromisoformat(selection['bound_at']).timestamp()):
27
+ return
28
+ if observed['outcome'] not in {'crashed', 'timed_out', 'spawn_failed', 'gave_up'}:
29
+ return
30
+ identity = {**native, 'native_run_id': state['native_run_id']}
31
+ source_id = 'native-runtime:' + hashlib.sha256(json.dumps(identity, sort_keys=True).encode()).hexdigest()
32
+ facts = {**observed, 'duration_seconds': ended-started, 'identity': identity,
33
+ 'registered_action': review['review']['action']}
34
+ message = {'role': 'assistant', '_native_runtime_observation': VERSION,
35
+ 'content': 'Runtime-owned internal review execution observation. '
36
+ 'This records lifecycle and elapsed time, not the accuracy of any output. '
37
+ 'Requested model configuration does not identify the serving processor.\n'
38
+ + json.dumps(facts, sort_keys=True)}
39
+ from apsimo.turns import get_turn_idempotency_ledger
40
+ from apsimo import get_state_dir
41
+ from apsimo.turns.idempotency import SourceErased
42
+ ledger = get_turn_idempotency_ledger(get_state_dir())
43
+ # Retain the first observation unchanged. Native task overrides can change
44
+ # after a run; observing it again must not rewrite that earlier evidence.
45
+ with closing(ledger._connect()) as conn:
46
+ if conn.execute('SELECT 1 FROM turn_sources WHERE turn_id=?', (source_id,)).fetchone():
47
+ return
48
+ try:
49
+ ledger.record_source(source_id, contact_id=owner,
50
+ session_id='native-runtime:'+native['native_task_id'], messages=[message],
51
+ occurred_at=datetime.fromtimestamp(ended, timezone.utc).isoformat(),
52
+ derive_claims=False, runtime_judgment=True)
53
+ except SourceErased:
54
+ # Normal observation replay must not resurrect an erased experience.
55
+ return
@@ -0,0 +1,220 @@
1
+ """AdaptiveParamStore -- bounded, journaled runtime parameters.
2
+
3
+ The meta-learning loop (CognitionPipeline -> StrategyAdjuster) needs a place
4
+ to write tuning adjustments that running subsystems actually READ BACK. This
5
+ store is that place: a small SQLite table of named float parameters, each
6
+ registered by its consumer with a default and hard bounds. Every write is
7
+ clamped to the registered bounds and journaled through the ActionJournal
8
+ (domain "meta_learning"), so a bad self-adjustment is visible, attributable,
9
+ and bounded -- never a silent behavior shift.
10
+
11
+ Consumers read at use-time (no restart needed). Writers (the strategy
12
+ adjuster, tools, or the owner via API) go through ``set()`` and never bypass
13
+ the clamp.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import logging
19
+ import sqlite3
20
+ import threading
21
+ import time
22
+ from typing import Any, Dict, List, Optional
23
+
24
+ from apsimo.self_model.benchmark import cognition_p4_mode
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ class AdaptiveParamStore:
30
+ """SQLite-backed named float parameters with hard bounds + journaling."""
31
+
32
+ def __init__(self, db_path: Optional[str] = None,
33
+ journal: Any = None) -> None:
34
+ self._lock = threading.RLock()
35
+ self._journal = journal
36
+ self._experiment_writer_id: Optional[str] = None
37
+ self._experiment_writer_token: Any = None
38
+ self._conn = sqlite3.connect(str(db_path) if db_path else ":memory:",
39
+ check_same_thread=False)
40
+ self._conn.row_factory = sqlite3.Row
41
+ with self._lock:
42
+ self._conn.execute(
43
+ """CREATE TABLE IF NOT EXISTS adaptive_params (
44
+ name TEXT PRIMARY KEY,
45
+ value REAL,
46
+ default_value REAL NOT NULL,
47
+ lo REAL NOT NULL,
48
+ hi REAL NOT NULL,
49
+ description TEXT,
50
+ reason TEXT,
51
+ source TEXT,
52
+ updated_at REAL
53
+ )""")
54
+ self._conn.commit()
55
+
56
+ def set_journal(self, journal: Any) -> None:
57
+ """Attach the ActionJournal after boot (it is created later than
58
+ this store in the server lifespan)."""
59
+ self._journal = journal
60
+
61
+ def claim_experiment_writer(self, writer_id: str) -> Any:
62
+ """Claim the one in-process capability that may mutate P4 knobs.
63
+
64
+ The object token is intentionally not serializable. The database still
65
+ records every mutation; this capability prevents legacy components
66
+ from racing the canonical ExperimentEngine inside one sidecar.
67
+ """
68
+
69
+ normalized = (writer_id or "").strip()
70
+ if not normalized:
71
+ raise ValueError("experiment writer id is required")
72
+ with self._lock:
73
+ if self._experiment_writer_id is None:
74
+ self._experiment_writer_id = normalized
75
+ self._experiment_writer_token = object()
76
+ elif self._experiment_writer_id != normalized:
77
+ raise RuntimeError(
78
+ "AdaptiveParamStore already has an ExperimentEngine writer")
79
+ return self._experiment_writer_token
80
+
81
+ def _assert_writer(self, writer_token: Any) -> None:
82
+ if cognition_p4_mode() == "off":
83
+ return
84
+ if (self._experiment_writer_token is None
85
+ or writer_token is not self._experiment_writer_token):
86
+ raise PermissionError(
87
+ "ExperimentEngine is the sole adaptive-parameter writer "
88
+ "while COLONY_COGNITION_P4_MODE is enabled")
89
+
90
+ # -- registration (consumers declare their knob + safe range) ---------
91
+ def register(self, name: str, default: float, lo: float, hi: float,
92
+ description: str = "") -> None:
93
+ """Idempotently declare a parameter. Bounds/default/description are
94
+ refreshed on re-registration; a previously set value is kept (but
95
+ re-clamped if the new bounds exclude it)."""
96
+ name = (name or "").strip()
97
+ if not name:
98
+ return
99
+ if lo > hi:
100
+ lo, hi = hi, lo
101
+ default = min(max(float(default), lo), hi)
102
+ with self._lock:
103
+ row = self._conn.execute(
104
+ "SELECT value FROM adaptive_params WHERE name=?",
105
+ (name,)).fetchone()
106
+ value = row["value"] if row is not None else None
107
+ if value is not None:
108
+ value = min(max(float(value), lo), hi)
109
+ self._conn.execute(
110
+ """INSERT INTO adaptive_params
111
+ (name, value, default_value, lo, hi, description, updated_at)
112
+ VALUES (?, ?, ?, ?, ?, ?, ?)
113
+ ON CONFLICT(name) DO UPDATE SET
114
+ value=?, default_value=?, lo=?, hi=?, description=?""",
115
+ (name, value, default, lo, hi, description, time.time(),
116
+ value, default, lo, hi, description))
117
+ self._conn.commit()
118
+
119
+ # -- reads -------------------------------------------------------------
120
+ def get(self, name: str, default: Optional[float] = None) -> float:
121
+ """Current value: the set value if any, else the registered default,
122
+ else the caller-supplied fallback (0.0 if none)."""
123
+ with self._lock:
124
+ row = self._conn.execute(
125
+ "SELECT value, default_value FROM adaptive_params WHERE name=?",
126
+ ((name or "").strip(),)).fetchone()
127
+ if row is None:
128
+ return float(default) if default is not None else 0.0
129
+ if row["value"] is not None:
130
+ return float(row["value"])
131
+ return float(row["default_value"])
132
+
133
+ # -- writes (clamped + journaled) ---------------------------------------
134
+ def set(self, name: str, value: float, *, reason: str = "",
135
+ source: str = "", writer_token: Any = None) -> Optional[float]:
136
+ """Set a parameter. Returns the APPLIED (clamped) value, or None if
137
+ the parameter was never registered (unknown knobs are refused --
138
+ a writer cannot invent parameters no consumer reads)."""
139
+ self._assert_writer(writer_token)
140
+ name = (name or "").strip()
141
+ with self._lock:
142
+ row = self._conn.execute(
143
+ "SELECT lo, hi, value FROM adaptive_params WHERE name=?",
144
+ (name,)).fetchone()
145
+ if row is None:
146
+ logger.warning("AdaptiveParamStore: refusing unregistered "
147
+ "param %r", name)
148
+ return None
149
+ applied = min(max(float(value), row["lo"]), row["hi"])
150
+ prior = row["value"]
151
+ self._conn.execute(
152
+ """UPDATE adaptive_params
153
+ SET value=?, reason=?, source=?, updated_at=?
154
+ WHERE name=?""",
155
+ (applied, reason, source, time.time(), name))
156
+ self._conn.commit()
157
+ clamped = abs(applied - float(value)) > 1e-9
158
+ logger.info("AdaptiveParamStore: %s %s -> %s%s (%s)", name,
159
+ prior, applied, " [clamped]" if clamped else "",
160
+ reason or source or "unattributed")
161
+ if self._journal is not None:
162
+ try:
163
+ self._journal.record(
164
+ "meta_learning",
165
+ f"adaptive param {name}: {prior} -> {applied}"
166
+ + (" (clamped)" if clamped else ""),
167
+ reasoning=reason, decision="acted",
168
+ outcome="applied", ref=source or "adaptive_params")
169
+ except Exception:
170
+ logger.debug("param journal write failed", exc_info=True)
171
+ return applied
172
+
173
+ def reset(self, name: str, *, reason: str = "", source: str = "",
174
+ writer_token: Any = None) -> None:
175
+ """Clear a set value so the registered default applies again."""
176
+ self._assert_writer(writer_token)
177
+ with self._lock:
178
+ self._conn.execute(
179
+ "UPDATE adaptive_params SET value=NULL, reason=?, source=?, "
180
+ "updated_at=? WHERE name=?",
181
+ (reason, source, time.time(), (name or "").strip()))
182
+ self._conn.commit()
183
+
184
+ def snapshot(self) -> List[Dict[str, Any]]:
185
+ with self._lock:
186
+ rows = self._conn.execute(
187
+ "SELECT * FROM adaptive_params ORDER BY name").fetchall()
188
+ out = []
189
+ for r in rows:
190
+ d = dict(r)
191
+ d["effective"] = (float(d["value"]) if d["value"] is not None
192
+ else float(d["default_value"]))
193
+ out.append(d)
194
+ return out
195
+
196
+ def close(self) -> None:
197
+ with self._lock:
198
+ try:
199
+ self._conn.close()
200
+ except Exception:
201
+ pass
202
+
203
+
204
+ # Canonical parameter names (registered at boot; consumers read these).
205
+ PARAM_CONSOLIDATION_THRESHOLD = "consolidation.similarity_threshold"
206
+ PARAM_RECALL_MIN_RELEVANCE = "recall.min_relevance"
207
+
208
+
209
+ def register_core_params(store: AdaptiveParamStore) -> None:
210
+ """Register the parameters core subsystems consume."""
211
+ store.register(
212
+ PARAM_CONSOLIDATION_THRESHOLD, default=0.92, lo=0.85, hi=0.98,
213
+ description="MemoryConsolidator merge threshold: pairs at or above "
214
+ "this similarity are deduplicated. Hard floor 0.85 so a "
215
+ "self-adjustment can never mass-merge distinct memories.")
216
+ store.register(
217
+ PARAM_RECALL_MIN_RELEVANCE, default=0.0, lo=0.0, hi=0.5,
218
+ description="ColonyGraph.recall drops vector hits scoring below "
219
+ "this. 0 = no filter; capped at 0.5 so retrieval can "
220
+ "never be starved by a self-adjustment.")
@@ -0,0 +1,246 @@
1
+ """Source-backed preferences and inspectable attention.
2
+
3
+ This is a portable working perspective, not feelings, a worldview or authority.
4
+ Original owner words stay in the canonical source ledger. Only explicit owner
5
+ preferences adjust optional research priority; prior automatic weights are history.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ from contextlib import closing
10
+ from copy import copy
11
+ from datetime import datetime, timezone
12
+ import json
13
+ import re
14
+ import time
15
+
16
+
17
+ DOMAINS = frozenset({'research', 'knowledge_acquisition'})
18
+ VERSION = 'owner-directed-perspective-v2'
19
+
20
+
21
+ def initialize(conn):
22
+ conn.execute('''CREATE TABLE IF NOT EXISTS self_preference_events (
23
+ id INTEGER PRIMARY KEY AUTOINCREMENT, owner_id TEXT NOT NULL,
24
+ pref_key TEXT NOT NULL, value_json TEXT NOT NULL,
25
+ source_turn_id TEXT NOT NULL, message_hash TEXT NOT NULL,
26
+ source_at TEXT NOT NULL, supersedes INTEGER,
27
+ UNIQUE(owner_id,pref_key,source_turn_id,message_hash))''')
28
+ # A value-free marker prevents erased sourced corrections from revealing
29
+ # an older unprovenanced cache value for the same preference.
30
+ conn.execute('''CREATE TABLE IF NOT EXISTS self_preference_keys (
31
+ owner_id TEXT NOT NULL,pref_key TEXT NOT NULL,latest_event_id INTEGER,latest_source_at TEXT NOT NULL,
32
+ PRIMARY KEY(owner_id,pref_key))''')
33
+ conn.execute('''CREATE TABLE IF NOT EXISTS self_opinion_revisions (
34
+ id INTEGER PRIMARY KEY AUTOINCREMENT, domain TEXT NOT NULL,
35
+ weight REAL NOT NULL, basis_json TEXT NOT NULL, basis_digest TEXT NOT NULL,
36
+ reason TEXT NOT NULL, updated_at REAL NOT NULL, version TEXT NOT NULL)''')
37
+ conn.execute('''CREATE TABLE IF NOT EXISTS self_attention (
38
+ slot INTEGER PRIMARY KEY CHECK(slot=1), snapshot_json TEXT NOT NULL,
39
+ observed_at REAL NOT NULL)''')
40
+
41
+
42
+ def erase_removed(conn, turn_id, session_id, retained):
43
+ from apsimo.turns.idempotency import source_message_hash
44
+ if not conn.execute("SELECT 1 FROM sqlite_master WHERE name='self_preference_events'").fetchone():
45
+ return
46
+ hashes = {source_message_hash(session_id, message) for message in retained}
47
+ rows = conn.execute('SELECT id,message_hash FROM self_preference_events WHERE source_turn_id=?', (turn_id,)).fetchall()
48
+ for row in rows:
49
+ if row['message_hash'] not in hashes:
50
+ conn.execute('DELETE FROM self_preference_events WHERE id=?', (row['id'],))
51
+ # Attention contains correction references/weights; do not retain a stale
52
+ # derived snapshot after deleting its source. The next decision rebuilds it.
53
+ conn.execute('DELETE FROM self_attention')
54
+
55
+
56
+ def _json(value):
57
+ return json.dumps(value, sort_keys=True, separators=(',', ':'), ensure_ascii=True)
58
+
59
+
60
+ class SelfPerspective:
61
+ def __init__(self, ledger, *, owner_id, clock=time.time):
62
+ self.ledger = ledger
63
+ self.owner_id = str(owner_id or '')
64
+ self.clock = clock
65
+ with closing(ledger._connect()) as conn, conn:
66
+ initialize(conn)
67
+ from apsimo.self_model.judgments import SelfJudgments
68
+ self.judgments = SelfJudgments(ledger, owner_id=self.owner_id, clock=clock)
69
+ from apsimo.self_model.appraisals import AppraisalStore
70
+ self.appraisals = AppraisalStore(ledger, owner_id=self.owner_id, clock=clock)
71
+
72
+ def observe_source(self, turn_id, learner):
73
+ """Learn only direct, attributed owner words; replay does not add votes."""
74
+ from apsimo.turns.idempotency import source_message_hash
75
+ if not self.owner_id:
76
+ return []
77
+ learned = []
78
+ with closing(self.ledger._connect()) as conn, conn:
79
+ conn.execute('BEGIN IMMEDIATE')
80
+ source = conn.execute("SELECT * FROM turn_sources WHERE turn_id=? AND contact_id=? AND scope='person'", (turn_id, self.owner_id)).fetchone()
81
+ if source is None:
82
+ return []
83
+ for message in json.loads(source['messages_json']):
84
+ if message.get('role') != 'user':
85
+ continue
86
+ text = message.get('content', '')
87
+ if isinstance(text, list):
88
+ text = '\n'.join(p.get('text', '') for p in text if p.get('type') in {'text', 'input_text'})
89
+ if not isinstance(text, str):
90
+ continue
91
+ updates = self._directives(text, learner)
92
+ for key, value in updates:
93
+ source_at = datetime.fromisoformat(source['occurred_at'] or source['ingested_at']).astimezone(timezone.utc).isoformat()
94
+ previous = conn.execute('SELECT id FROM self_preference_events WHERE owner_id=? AND pref_key=? AND source_at<=? ORDER BY source_at DESC,id DESC LIMIT 1', (self.owner_id, key, source_at)).fetchone()
95
+ cur = conn.execute('''INSERT OR IGNORE INTO self_preference_events
96
+ (owner_id,pref_key,value_json,source_turn_id,message_hash,source_at,supersedes)
97
+ VALUES (?,?,?,?,?,?,?)''', (self.owner_id, key, _json(value), turn_id,
98
+ source_message_hash(source['session_id'], message),
99
+ source_at, previous['id'] if previous else None))
100
+ if cur.rowcount:
101
+ conn.execute('''INSERT INTO self_preference_keys VALUES (?,?,?,?)
102
+ ON CONFLICT(owner_id,pref_key) DO UPDATE SET latest_event_id=excluded.latest_event_id,
103
+ latest_source_at=excluded.latest_source_at WHERE excluded.latest_source_at>=self_preference_keys.latest_source_at''',
104
+ (self.owner_id, key, cur.lastrowid, source_at))
105
+ learned.append((key, value))
106
+ return learned
107
+
108
+ @staticmethod
109
+ def _directives(text, learner):
110
+ raw = text.strip()
111
+ # Conservative direct-address subset. Quotation, questions, reports
112
+ # about another person and ambiguous negation remain raw evidence.
113
+ if len(raw.split()) > 40 or any(c in raw for c in ('"', '“', '”', '?', '`', '\n')):
114
+ return []
115
+ operational = re.fullmatch(r'(?:please\s+)?(prefer|deprioritize|use normal priority for)\s+(research|knowledge acquisition)\s+initiatives[.!]?', raw, re.I)
116
+ if operational:
117
+ weight = {'prefer': 1.2, 'deprioritize': 0.8, 'use normal priority for': 1.0}[operational[1].lower()]
118
+ return [('initiative.' + operational[2].lower().replace(' ', '_'), weight)]
119
+ prefix = re.match(r'^(?:(?:please|actually|from now on|going forward)[,:]?\s+)*(?:be\b|keep\b|use\b|stop\b|skip\b|avoid\b|don.t\b|do not\b|no emoji\b|no emojis\b|i prefer\b|i want\b)', raw, re.I)
120
+ if not prefix:
121
+ return []
122
+ # Reuse existing style vocabulary, but do not guess the direction of
123
+ # a negated or comparative request from bag-of-words keyword order.
124
+ polarity = re.sub(r'\b(?:stop\s+(?:using\s+|with\s+)?|skip\s+(?:the\s+)?|avoid\s+(?:the\s+)?|no\s+|don.t\s+use\s+|do\s+not\s+use\s+)emojis?\b', '', raw, flags=re.I)
125
+ if re.search(r'\b(not|never|rather|instead|than|except|without|don.t|stop|skip|avoid|no)\b', polarity, re.I):
126
+ return []
127
+ from apsimo.intelligence.components import preference_learner as vocabulary
128
+ words = set(re.findall(r'\b\w+\b', raw.lower()))
129
+ if re.search(r'\bi (?:prefer|want)$', prefix[0], re.I):
130
+ # First-person corrections must name general communication:
131
+ # "I prefer/want <style> replies/responses/answers". Artifact
132
+ # requests ("I want a code example") remain ordinary evidence.
133
+ general = re.fullmatch(r'(.+?)\s+(?:replies|responses|answers)[.!]?', raw[prefix.end():].strip(), re.I)
134
+ if general is None or set(re.findall(r'\b\w+\b', general[1].lower())) - (vocabulary._STYLE_KEYWORDS | {'and', 'more'}):
135
+ return []
136
+ words.discard('i')
137
+ style_words = vocabulary._STYLE_KEYWORDS | vocabulary._DIRECTIVE_CUES | vocabulary._NEGATION | {'and', 'the', 't', 'a', 'an', 'of', 'with', 'so', 'being', 'all', 'future', 'my', 'me', 'actually'}
138
+ if words - style_words:
139
+ return [] # Content/task-specific instructions are not standing style corrections.
140
+ for alternatives in ((vocabulary._LENGTH_SHORT, vocabulary._LENGTH_LONG, vocabulary._LENGTH_MEDIUM),
141
+ (vocabulary._FORMAT_BULLETS, vocabulary._FORMAT_PROSE, vocabulary._FORMAT_TABLE),
142
+ (vocabulary._STYLE_FORMAL, vocabulary._STYLE_CASUAL)):
143
+ if sum(bool(words & option) for option in alternatives) > 1:
144
+ return []
145
+ if not learner.detect_directive(raw):
146
+ return []
147
+ return [('communication_style.' + key, value) for key, value in learner._parse_all(raw)]
148
+
149
+ def preferences(self, *, history=False):
150
+ from apsimo.turns.idempotency import source_message_hash
151
+ with closing(self.ledger._connect()) as conn:
152
+ heads = {r[0]: r[1] for r in conn.execute('SELECT pref_key,latest_event_id FROM self_preference_keys WHERE owner_id=?', (self.owner_id,))}
153
+ query = '''SELECT p.*,s.session_id,s.messages_json FROM self_preference_events p
154
+ JOIN turn_sources s ON s.turn_id=p.source_turn_id
155
+ WHERE p.owner_id=? AND s.contact_id=? AND s.scope='person' '''
156
+ if not history:
157
+ query += 'AND p.id IN (SELECT latest_event_id FROM self_preference_keys WHERE owner_id=p.owner_id) '
158
+ query += 'ORDER BY p.source_at DESC,p.id DESC'
159
+ if history:
160
+ query += ' LIMIT 100'
161
+ rows = conn.execute(query, (self.owner_id, self.owner_id)).fetchall()
162
+ result, seen = [], set()
163
+ for row in rows:
164
+ if row['message_hash'] not in {source_message_hash(row['session_id'], m) for m in json.loads(row['messages_json'])}:
165
+ continue
166
+ if not history and (row['pref_key'] in seen or row['id'] != heads.get(row['pref_key'])):
167
+ continue
168
+ seen.add(row['pref_key'])
169
+ result.append({key: row[key] for key in ('id', 'pref_key', 'source_turn_id', 'message_hash', 'source_at', 'supersedes')} | {'value': json.loads(row['value_json']), 'basis': 'owner_correction'})
170
+ return result
171
+
172
+ def tracked_keys(self):
173
+ with closing(self.ledger._connect()) as conn:
174
+ return {r[0] for r in conn.execute('SELECT pref_key FROM self_preference_keys WHERE owner_id=?', (self.owner_id,))}
175
+
176
+ def opinions(self, *, history=False):
177
+ """Retained automatic revisions are inspectable, never governing."""
178
+ with closing(self.ledger._connect()) as conn:
179
+ query = ('SELECT * FROM self_opinion_revisions ORDER BY id DESC LIMIT 100' if history else
180
+ 'SELECT * FROM self_opinion_revisions WHERE id IN (SELECT max(id) FROM self_opinion_revisions GROUP BY domain) ORDER BY domain')
181
+ rows = conn.execute(query).fetchall()
182
+ return [dict(row) | {'basis': json.loads(row['basis_json']),
183
+ 'status': 'legacy_non_governing', 'governing': False} for row in rows]
184
+
185
+ def rank(self, initiatives, *, competence=None, load=None):
186
+ # competence is retained as a call-compatibility argument, never consumed.
187
+ initiatives = [copy(item) for item in initiatives] # no compounding on cached engine candidates
188
+ with closing(self.ledger._connect()) as conn, conn:
189
+ conn.execute('BEGIN IMMEDIATE')
190
+ overrides = {row['pref_key'].removeprefix('initiative.'): row for row in self.preferences() if row['pref_key'].startswith('initiative.')}
191
+ decisions = []
192
+ for item in initiatives:
193
+ domain = getattr(item.type, 'value', str(item.type))
194
+ original = float(item.priority)
195
+ override = overrides.get(domain)
196
+ weight = float(override['value']) if override else 1.0
197
+ # Due/urgent and non-research work keeps its existing urgency.
198
+ applied = override is not None and domain in DOMAINS and original < 0.9
199
+ item.priority = round(max(0.0, min(0.89, original * weight)), 4) if applied else original
200
+ decisions.append({'initiative_id': str(item.id), 'domain': domain, 'original_priority': original,
201
+ 'description': str(getattr(item, 'description', '') or '')[:500],
202
+ 'priority': item.priority, 'weight': weight if applied else 1.0,
203
+ 'basis': 'owner_correction' if override and applied else 'unchanged',
204
+ 'correction_id': override['id'] if override and applied else None,
205
+ 'opinion_revision': None})
206
+ ranked = sorted(initiatives, key=lambda item: -item.priority)
207
+ snapshot = {'version': VERSION, 'load': dict(load or {}), 'decisions': decisions,
208
+ 'ordered_ids': [str(item.id) for item in ranked], 'authority_changed': False,
209
+ 'load_coverage': 'existing initiative/project/queue probes; missing sources are not proven idle'}
210
+ conn.execute('INSERT OR REPLACE INTO self_attention VALUES (1,?,?)', (_json(snapshot), self.clock()))
211
+ return ranked
212
+
213
+ def status(self):
214
+ with closing(self.ledger._connect()) as conn:
215
+ row = conn.execute('SELECT * FROM self_attention WHERE slot=1').fetchone()
216
+ attention = None
217
+ if row is not None:
218
+ snapshot = json.loads(row['snapshot_json'])
219
+ attention = snapshot | {'observed_at': row['observed_at'],
220
+ 'age_seconds': max(0, round(self.clock() - row['observed_at'], 1)),
221
+ 'historical_only': snapshot.get('version') != VERSION}
222
+ return {'kind': 'operational_working_perspective', 'preferences': self.preferences(),
223
+ 'corrections': self.preferences(history=True), 'opinions': self.opinions(),
224
+ 'judgments_enabled': self.judgments.enabled,
225
+ 'judgments': self.judgments.revisions(), 'judgment_history': self.judgments.revisions(history=True),
226
+ 'judgment_processing': self.judgments.processing(),
227
+ 'appraisals': self.appraisals.view(self.owner_id, viewer_contact_id=self.owner_id,
228
+ history=True, limit=10),
229
+ 'opinion_history': self.opinions(history=True), 'automatic_weighting': 'retired', 'attention': attention}
230
+
231
+ def brief(self, query='', *, source_ids=None):
232
+ lines = []
233
+ for pref in self.preferences():
234
+ if pref['pref_key'].startswith('initiative.'):
235
+ lines.append(f"Owner correction: {pref['pref_key']} priority weight {pref['value']:.2f}; source turn:{pref['source_turn_id']}; applies only to optional research ordering.")
236
+ if source_ids is not None:
237
+ source_ids.append(pref['source_turn_id'])
238
+ state = self.status()['attention']
239
+ if state is not None and not state['historical_only']:
240
+ lines.append(f"Last initiative ranking, {state['age_seconds']:g}s ago: " + ', '.join(state['ordered_ids'][:8]) + '. This is a decision snapshot, not current liveness.')
241
+ if lines:
242
+ lines.append('Only explicit owner preferences adjust these priorities. Runtime history establishes neither output quality nor the competence of the current model; it grants no authority.')
243
+ judgments = self.judgments.brief(query, source_ids=source_ids)
244
+ if judgments:
245
+ lines.append(judgments)
246
+ return '\n'.join(lines)