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,270 @@
1
+ """Goal Priority Scoring and Progress Tracking.
2
+
3
+ GoalPriorityScorer: composite priority score with urgency decay, importance,
4
+ user preferences, blocking bonus, and age decay.
5
+
6
+ GoalProgressTracker: weighted completion fraction and completion time estimation.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import math
12
+ from dataclasses import dataclass, field
13
+ from datetime import datetime, timezone
14
+ from typing import Dict, List, Optional
15
+
16
+ from apsimo.goals.models import Goal, GoalDAG, GoalPriority, SubtaskStatus
17
+
18
+
19
+ @dataclass
20
+ class PriorityScore:
21
+ """Composite priority score with component breakdown."""
22
+ total: float # 0.0–100.0 final score
23
+ urgency: float # Deadline proximity component
24
+ importance: float # User-stated importance component
25
+ preference_bonus: float # Learned preference modifier
26
+ blocking_penalty: float # Bonus if goal is blocking other goals
27
+ age_decay: float # Score decay for stale goals
28
+ breakdown: Dict[str, float] = field(default_factory=dict)
29
+
30
+
31
+ @dataclass
32
+ class UserPreferenceProfile:
33
+ """Learned user preferences influencing goal prioritization.
34
+
35
+ Attributes:
36
+ domain_weights: Per-domain priority multipliers (e.g., "health": 1.3).
37
+ preferred_hours: Hours of day when the user prefers work to execute.
38
+ completion_patterns: Historical goal completion rates by category.
39
+ avoidance_domains: Domains the user tends to defer or abandon.
40
+ """
41
+ domain_weights: Dict[str, float] = field(default_factory=dict)
42
+ preferred_hours: List[int] = field(default_factory=list)
43
+ completion_patterns: Dict[str, float] = field(default_factory=dict)
44
+ avoidance_domains: List[str] = field(default_factory=list)
45
+
46
+ # EMA smoothing factor for learning (α = 0.3 → weights recent behavior ~3× more)
47
+ ema_alpha: float = 0.3
48
+
49
+ def update_domain_completion(self, domain: str, success: bool) -> None:
50
+ """Update completion pattern for a domain using EMA."""
51
+ value = 1.0 if success else 0.0
52
+ if domain in self.completion_patterns:
53
+ old = self.completion_patterns[domain]
54
+ self.completion_patterns[domain] = self.ema_alpha * value + (1 - self.ema_alpha) * old
55
+ else:
56
+ self.completion_patterns[domain] = value
57
+
58
+ def update_domain_weight(self, domain: str, delta: float) -> None:
59
+ """Adjust domain weight using EMA."""
60
+ current = self.domain_weights.get(domain, 1.0)
61
+ new_weight = self.ema_alpha * (current + delta) + (1 - self.ema_alpha) * current
62
+ self.domain_weights[domain] = max(0.1, min(3.0, new_weight))
63
+
64
+
65
+ def _deadline_urgency(goal: Goal) -> float:
66
+ """Compute urgency in [0, 1] based on deadline proximity.
67
+
68
+ urgency(t) = 1 / (1 + exp(-k * (t_remaining_fraction - 0.5)))
69
+ where k = 10 (steepness constant)
70
+ """
71
+ if goal.deadline is None:
72
+ return 0.0
73
+
74
+ now = datetime.now(timezone.utc)
75
+ if now >= goal.deadline:
76
+ return 1.0
77
+
78
+ total_window = (goal.deadline - goal.created_at).total_seconds()
79
+ if total_window <= 0:
80
+ return 1.0
81
+
82
+ remaining = (goal.deadline - now).total_seconds()
83
+ t_remaining_fraction = remaining / total_window
84
+
85
+ k = 10.0
86
+ urgency = 1.0 / (1.0 + math.exp(-k * (t_remaining_fraction - 0.5)))
87
+ # Invert so that low remaining fraction = high urgency
88
+ return round(1.0 - urgency, 4)
89
+
90
+
91
+ def _base_importance(goal: Goal) -> float:
92
+ """Derive importance from goal's explicit priority (normalised to [0, 1])."""
93
+ return goal.priority.value / 100.0
94
+
95
+
96
+ def _preference_modifier(goal: Goal, preferences: UserPreferenceProfile) -> float:
97
+ """Compute preference bonus in [0, 1] from user preference profile."""
98
+ # Use goal tags to determine domain
99
+ domain = goal.tags.get("domain", "")
100
+ if not domain:
101
+ return 0.0
102
+
103
+ weight = preferences.domain_weights.get(domain, 1.0)
104
+ # Map weight (typically 0.1–3.0) to a bonus in [0, 1]
105
+ bonus = min(1.0, max(0.0, (weight - 1.0) / 2.0))
106
+ return round(bonus, 4)
107
+
108
+
109
+ def _blocking_bonus(goal: Goal, all_goals: Optional[List[Goal]] = None) -> float:
110
+ """Return 1.0 if this goal is a dependency (parent) for other active goals."""
111
+ if all_goals is None:
112
+ return 0.0
113
+ for other in all_goals:
114
+ if other.parent_goal_id == goal.goal_id and not other.is_terminal():
115
+ return 1.0
116
+ return 0.0
117
+
118
+
119
+ def _age_decay(goal: Goal) -> float:
120
+ """Compute staleness penalty in [0, 1] for old untouched goals."""
121
+ age = goal.age_hours()
122
+ # Penalty grows logarithmically; at 168 hours (1 week) = ~0.5
123
+ if age < 1:
124
+ return 0.0
125
+ return round(min(1.0, math.log(age) / math.log(168.0)), 4)
126
+
127
+
128
+ class GoalPriorityScorer:
129
+ """Compute composite priority scores for goals."""
130
+
131
+ WEIGHTS = {
132
+ "urgency": 0.35,
133
+ "importance": 0.30,
134
+ "preference_bonus": 0.15,
135
+ "blocking": 0.10,
136
+ "age_decay": -0.10, # Negative — reduces priority for very old stale goals
137
+ }
138
+
139
+ def score(
140
+ self,
141
+ goal: Goal,
142
+ preferences: Optional[UserPreferenceProfile] = None,
143
+ all_goals: Optional[List[Goal]] = None,
144
+ ) -> PriorityScore:
145
+ """Compute a composite priority score for a goal.
146
+
147
+ Components:
148
+ - urgency: deadline_urgency(goal) — 0.0 if no deadline, 1.0 if overdue
149
+ - importance: base_importance(goal) — from user tags, source, explicit priority
150
+ - preference: preference_modifier(goal, preferences) — domain preference bonus
151
+ - blocking: is_blocking_bonus(goal) — if other goals depend on this one
152
+ - age_decay: stale_penalty(goal) — reduces priority for untouched old goals
153
+ """
154
+ prefs = preferences or UserPreferenceProfile()
155
+
156
+ urgency = _deadline_urgency(goal)
157
+ importance = _base_importance(goal)
158
+ preference = _preference_modifier(goal, prefs)
159
+ blocking = _blocking_bonus(goal, all_goals)
160
+ decay = _age_decay(goal)
161
+
162
+ components = {
163
+ "urgency": urgency,
164
+ "importance": importance,
165
+ "preference_bonus": preference,
166
+ "blocking": blocking,
167
+ "age_decay": decay,
168
+ }
169
+
170
+ total = 100.0 * (
171
+ self.WEIGHTS["urgency"] * urgency
172
+ + self.WEIGHTS["importance"] * importance
173
+ + self.WEIGHTS["preference_bonus"] * preference
174
+ + self.WEIGHTS["blocking"] * blocking
175
+ + self.WEIGHTS["age_decay"] * decay # this is negative
176
+ )
177
+ total = max(0.0, min(100.0, total))
178
+
179
+ return PriorityScore(
180
+ total=round(total, 2),
181
+ urgency=urgency,
182
+ importance=importance,
183
+ preference_bonus=preference,
184
+ blocking_penalty=blocking,
185
+ age_decay=decay,
186
+ breakdown=components,
187
+ )
188
+
189
+ def rank_goals(
190
+ self,
191
+ goals: List[Goal],
192
+ preferences: Optional[UserPreferenceProfile] = None,
193
+ ) -> List[Goal]:
194
+ """Return goals sorted by descending priority score."""
195
+ scored = [(g, self.score(g, preferences, goals).total) for g in goals]
196
+ scored.sort(key=lambda x: x[1], reverse=True)
197
+ return [g for g, _ in scored]
198
+
199
+
200
+ class GoalProgressTracker:
201
+ """Track and report goal progress."""
202
+
203
+ def update_progress(self, goal_id: str, dag: GoalDAG) -> float:
204
+ """Recompute progress fraction from subtask statuses.
205
+
206
+ Weights subtasks on the critical path more heavily (2× weight).
207
+
208
+ Returns updated progress_pct (0.0–1.0).
209
+ """
210
+ total_weight = 0.0
211
+ done_weight = 0.0
212
+
213
+ for s in dag.subtasks.values():
214
+ weight = 2.0 if s.is_critical_path else 1.0
215
+ total_weight += weight
216
+ if s.status in {SubtaskStatus.COMPLETED, SubtaskStatus.SKIPPED}:
217
+ done_weight += weight
218
+
219
+ return done_weight / total_weight if total_weight > 0 else 0.0
220
+
221
+ def estimate_completion(
222
+ self,
223
+ goal: Goal,
224
+ dag: GoalDAG,
225
+ historical_perf: Optional[Dict[str, float]] = None,
226
+ ) -> Optional[datetime]:
227
+ """Estimate completion time based on critical path remaining work.
228
+
229
+ Uses three-point estimation:
230
+ estimated_remaining = sum(subtask.estimated_hours * perf_factor)
231
+ for remaining critical path subtasks.
232
+
233
+ Returns estimated completion datetime, or None if not estimable.
234
+ """
235
+ if not dag.critical_path:
236
+ return None
237
+
238
+ perf = historical_perf or {}
239
+ remaining_hours = 0.0
240
+ for sid in dag.critical_path:
241
+ subtask = dag.subtasks.get(sid)
242
+ if subtask is None:
243
+ continue
244
+ if subtask.status in {SubtaskStatus.COMPLETED, SubtaskStatus.SKIPPED}:
245
+ continue
246
+ est = subtask.estimated_hours if subtask.estimated_hours is not None else 1.0
247
+ pf = perf.get(subtask.job_type, 1.0)
248
+ remaining_hours += est * pf
249
+
250
+ if remaining_hours <= 0:
251
+ return None
252
+
253
+ from datetime import timedelta
254
+ return datetime.now(timezone.utc) + timedelta(hours=remaining_hours)
255
+
256
+ def check_blocked(self, goal: "Goal", dag: GoalDAG) -> Optional[str]:
257
+ """Return a reason string if the goal appears blocked, else None."""
258
+ ready = dag.ready_subtasks()
259
+ if ready:
260
+ return None # Work available
261
+
262
+ # Check if there are non-terminal subtasks with unmet deps
263
+ for s in dag.subtasks.values():
264
+ if s.status in {SubtaskStatus.PENDING, SubtaskStatus.BLOCKED}:
265
+ # All deps failed?
266
+ for dep_id in s.depends_on:
267
+ dep = dag.subtasks.get(dep_id)
268
+ if dep and dep.status == SubtaskStatus.FAILED:
269
+ return f"Subtask {s.subtask_id} blocked by failed dependency {dep_id}"
270
+ return None
@@ -0,0 +1,149 @@
1
+ """GoalQueueBridge — integrate Goal Engine with the distributed task queue.
2
+
3
+ Converts Subtask nodes into task queue Jobs, dispatches ready subtasks,
4
+ and processes job results to update goal/subtask state.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ from typing import Any, Callable, Dict, List, Optional, Protocol
11
+
12
+ from apsimo.goals.models import (
13
+ Goal,
14
+ GoalDAG,
15
+ GoalPriority,
16
+ GoalStatus,
17
+ Subtask,
18
+ SubtaskStatus,
19
+ )
20
+ from apsimo.task_queue.models import (
21
+ Job,
22
+ JobCapabilityRequirement,
23
+ JobPriority,
24
+ JobResult,
25
+ JobType,
26
+ )
27
+
28
+ logger = logging.getLogger(__name__)
29
+
30
+ # Priority mapping: GoalPriority → JobPriority
31
+ _PRIORITY_MAP: Dict[int, JobPriority] = {
32
+ GoalPriority.BACKGROUND: JobPriority.BACKGROUND,
33
+ GoalPriority.LOW: JobPriority.LOW,
34
+ GoalPriority.NORMAL: JobPriority.NORMAL,
35
+ GoalPriority.HIGH: JobPriority.HIGH,
36
+ GoalPriority.CRITICAL: JobPriority.CRITICAL,
37
+ }
38
+
39
+
40
+ def _map_priority(goal_priority: GoalPriority) -> JobPriority:
41
+ return _PRIORITY_MAP.get(goal_priority.value, JobPriority.NORMAL)
42
+
43
+
44
+ def _job_type_from_string(job_type: str) -> JobType:
45
+ """Convert subtask job_type string to JobType enum (with fallback)."""
46
+ try:
47
+ return JobType(job_type)
48
+ except ValueError:
49
+ return JobType.CUSTOM
50
+
51
+
52
+ class QueueBackend(Protocol):
53
+ """Minimal interface expected from the task queue."""
54
+
55
+ def post(self, job: Job) -> str:
56
+ """Post a job and return its job_id."""
57
+ ...
58
+
59
+
60
+ class InMemoryQueueBackend:
61
+ """Simple in-memory queue backend for testing without a real queue."""
62
+
63
+ def __init__(self) -> None:
64
+ self._jobs: Dict[str, Job] = {}
65
+ self._posted_order: List[str] = []
66
+
67
+ def post(self, job: Job) -> str:
68
+ self._jobs[job.job_id] = job
69
+ self._posted_order.append(job.job_id)
70
+ logger.debug("InMemoryQueue: posted job %s (type=%s)", job.job_id, job.job_type)
71
+ return job.job_id
72
+
73
+ def get_job(self, job_id: str) -> Optional[Job]:
74
+ return self._jobs.get(job_id)
75
+
76
+ def list_jobs(self) -> List[Job]:
77
+ return [self._jobs[jid] for jid in self._posted_order if jid in self._jobs]
78
+
79
+
80
+ class GoalQueueBridge:
81
+ """Bridge between the Goal Engine and the distributed task queue."""
82
+
83
+ def __init__(self, queue: Optional[QueueBackend] = None) -> None:
84
+ # A missing production binding must not silently become a test queue.
85
+ self._queue = queue
86
+
87
+ @property
88
+ def available(self) -> bool:
89
+ """Whether a caller supplied a backend, not proof of worker liveness."""
90
+ return self._queue is not None
91
+
92
+ def subtask_to_job(self, goal: Goal, subtask: Subtask) -> Job:
93
+ """Convert a ready Subtask into a task queue Job.
94
+
95
+ Priority mapping:
96
+ GoalPriority.CRITICAL → JobPriority.CRITICAL
97
+ GoalPriority.HIGH → JobPriority.HIGH
98
+ GoalPriority.NORMAL → JobPriority.NORMAL
99
+ GoalPriority.LOW → JobPriority.LOW
100
+ GoalPriority.BACKGROUND → JobPriority.BACKGROUND
101
+
102
+ Deadline: goal.deadline is forwarded if set.
103
+ """
104
+ return Job(
105
+ job_type=_job_type_from_string(subtask.job_type),
106
+ payload={
107
+ "goal_id": goal.goal_id,
108
+ "subtask_id": subtask.subtask_id,
109
+ **subtask.payload,
110
+ },
111
+ priority=_map_priority(goal.priority),
112
+ capabilities=[
113
+ JobCapabilityRequirement(name=cap)
114
+ for cap in subtask.capabilities
115
+ ],
116
+ deadline=goal.deadline,
117
+ tags={
118
+ "goal_id": goal.goal_id,
119
+ "goal_title": goal.title[:64],
120
+ },
121
+ )
122
+
123
+ def dispatch_ready_subtasks(self, goal: Goal, dag: GoalDAG) -> int:
124
+ """Dispatch all ready subtasks to the task queue.
125
+
126
+ Returns the number of jobs posted.
127
+ """
128
+ if self._queue is None:
129
+ return 0
130
+ count = 0
131
+ for subtask in dag.ready_subtasks():
132
+ job = self.subtask_to_job(goal, subtask)
133
+ job_id = self._queue.post(job)
134
+ subtask.job_id = job_id
135
+ subtask.status = SubtaskStatus.DISPATCHED
136
+ count += 1
137
+ logger.info(
138
+ "Dispatched subtask %s (job_id=%s) for goal %s",
139
+ subtask.subtask_id, job_id, goal.goal_id,
140
+ )
141
+ return count
142
+
143
+ def cancel_all_jobs(self, dag: GoalDAG) -> None:
144
+ """Cancel all dispatched/running jobs in the DAG (best-effort)."""
145
+ for subtask in dag.subtasks.values():
146
+ if subtask.status in {SubtaskStatus.DISPATCHED, SubtaskStatus.RUNNING}:
147
+ subtask.status = SubtaskStatus.FAILED
148
+ subtask.error = "Job cancelled: goal abandoned"
149
+ logger.info("Cancelled job for subtask %s", subtask.subtask_id)