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,441 @@
1
+ """Claim Colony agent_action jobs and hand them to the agent.
2
+
3
+ Installed as the ``colony-queue-worker`` console script (v0.20.0); the
4
+ logic moved here unchanged from
5
+ ``plugins/hermes-plugin/poller/colony-queue-worker.py`` (v0.16.0),
6
+ which remains as a thin back-compat wrapper.
7
+
8
+ This is the execution half of the agent-as-sensor loop:
9
+
10
+ Colony notices a domain is stale → posts a read-only agent_sync_<domain>
11
+ job → THIS worker claims it and fires it to the agent webhook → the
12
+ agent observes through its own toolsets (github, terminal, web, ...) →
13
+ the agent POSTs observations back to Colony and completes the job →
14
+ Colony generates initiatives from what the agent saw.
15
+
16
+ The same path carries every other registered agent_action capability.
17
+ Run from cron every few minutes (the wizard installs ``*/5 * * * *``).
18
+ Without it, auto-approved agent_action jobs sit QUEUED forever.
19
+
20
+ The webhook prompt receives explicit lifecycle URLs so the agent can
21
+ close the loop with plain curl — no special tooling needed:
22
+
23
+ - report observations: POST {COLONY_URL}/v1/host/observations
24
+ - complete the job: POST {COLONY_URL}/v1/host/queue/jobs/{id}/complete
25
+ - fail the job: POST {COLONY_URL}/v1/host/queue/jobs/{id}/fail
26
+
27
+ Environment (unchanged from the v0.16 script):
28
+ COLONY_URL sidecar URL (default http://127.0.0.1:7777)
29
+ COLONY_API_KEY API key (default dev-mode-no-key)
30
+ COLONY_JOBS_WEBHOOK_URL agent webhook (default http://127.0.0.1:8644/webhooks/colony-jobs)
31
+ COLONY_WORKER_NODE_ID worker identity (default derived from COLONY_AGENT_NAME)
32
+ COLONY_WORKER_MAX_JOBS jobs per run (default 1 — each is a full agent invocation)
33
+ COLONY_AGENT_WORKER_ROUTES comma-separated exact no-effect lanes:
34
+ agent_sync, hermes_run (default both)
35
+
36
+ Stdlib-only on purpose — must run from cron without the sidecar deps.
37
+ """
38
+
39
+ from __future__ import annotations
40
+
41
+ import argparse
42
+ import hashlib
43
+ import hmac
44
+ import json
45
+ import os
46
+ import time
47
+ import urllib.request
48
+ from datetime import datetime, timezone
49
+ from typing import Any, Dict, Optional
50
+
51
+
52
+ _AGENT_ACTION_BASE_CAPABILITIES = [
53
+ "agent_action",
54
+ "filesystem:read",
55
+ "memory:read",
56
+ "reasoning",
57
+ "web:read",
58
+ ]
59
+
60
+ _AGENT_ACTION_ROUTE_CAPABILITY = {
61
+ "agent_sync": "agent_sync:v1",
62
+ "hermes_run": "hermes_run:v1",
63
+ }
64
+
65
+
66
+ def agent_action_capabilities(routes: Optional[str] = None) -> list[str]:
67
+ """Return the exact configured generic lanes, rejecting ambiguity."""
68
+
69
+ configured = (
70
+ os.environ.get("COLONY_AGENT_WORKER_ROUTES", "agent_sync,hermes_run")
71
+ if routes is None else routes
72
+ )
73
+ selected = {
74
+ item.strip().lower()
75
+ for item in str(configured or "").split(",")
76
+ if item.strip()
77
+ }
78
+ unknown = selected - set(_AGENT_ACTION_ROUTE_CAPABILITY)
79
+ if not selected or unknown:
80
+ detail = ",".join(sorted(unknown)) if unknown else "empty"
81
+ raise ValueError(
82
+ "COLONY_AGENT_WORKER_ROUTES must select agent_sync and/or "
83
+ f"hermes_run (invalid: {detail})"
84
+ )
85
+ return [
86
+ *_AGENT_ACTION_BASE_CAPABILITIES,
87
+ *(
88
+ _AGENT_ACTION_ROUTE_CAPABILITY[name]
89
+ for name in ("agent_sync", "hermes_run")
90
+ if name in selected
91
+ ),
92
+ ]
93
+
94
+
95
+ # Backward-compatible import for callers that intentionally use the combined
96
+ # generic pool. Runtime worker registration/claims use the function above so
97
+ # separate sync and text principals can advertise exact disjoint grants.
98
+ AGENT_ACTION_CAPABILITIES = agent_action_capabilities(
99
+ "agent_sync,hermes_run"
100
+ )
101
+
102
+
103
+ def encode_hermes_webhook(
104
+ payload: Dict[str, Any],
105
+ *,
106
+ secret: Optional[str] = None,
107
+ timestamp: Optional[int] = None,
108
+ ) -> tuple[bytes, Dict[str, str]]:
109
+ """Serialize once and add Hermes' replay-resistant V2 HMAC."""
110
+
111
+ body = json.dumps(
112
+ payload, separators=(",", ":"), default=str,
113
+ ).encode("utf-8")
114
+ headers = {"Content-Type": "application/json"}
115
+ configured = (
116
+ os.environ.get("COLONY_HERMES_WEBHOOK_SECRET", "")
117
+ if secret is None else secret
118
+ )
119
+ configured = str(configured or "")
120
+ if configured and configured != "INSECURE_NO_AUTH":
121
+ issued_at = int(time.time()) if timestamp is None else int(timestamp)
122
+ signed = str(issued_at).encode("ascii") + b"." + body
123
+ headers.update({
124
+ "X-Webhook-Timestamp": str(issued_at),
125
+ "X-Webhook-Signature-V2": hmac.new(
126
+ configured.encode("utf-8"), signed, hashlib.sha256,
127
+ ).hexdigest(),
128
+ })
129
+ if os.environ.get(
130
+ "COLONY_HERMES_WEBHOOK_V1_COMPAT", "false"
131
+ ).strip().lower() in {"1", "true", "yes", "on"}:
132
+ headers["X-Webhook-Signature"] = hmac.new(
133
+ configured.encode("utf-8"), body, hashlib.sha256,
134
+ ).hexdigest()
135
+ inner = payload.get("payload") if isinstance(payload, dict) else None
136
+ if isinstance(inner, dict):
137
+ request_id = str(
138
+ inner.get("claim_attempt_id")
139
+ or inner.get("job_id")
140
+ or inner.get("id")
141
+ or ""
142
+ ).strip()
143
+ if request_id:
144
+ headers["X-Request-ID"] = request_id[:256]
145
+ return body, headers
146
+
147
+
148
+ def work_order_webhook_fields(params: Dict[str, Any]) -> Dict[str, Any]:
149
+ """Return the bounded WorkOrder contract needed by an agent webhook."""
150
+
151
+ if params.get("schema") != "WorkOrderV1":
152
+ return {}
153
+ fields = (
154
+ "schema", "version", "source", "work_order_id",
155
+ "work_order_digest", "project_id", "step_id", "step_ordinal",
156
+ "objective", "success_criteria",
157
+ "context_refs", "capability_allowlist", "risk_class",
158
+ "recipient_scope", "max_runtime_seconds", "max_attempts",
159
+ "issued_at", "deadline", "action_hint",
160
+ )
161
+ order = {name: params.get(name) for name in fields}
162
+ effect_class = (
163
+ params.get("risk_class")
164
+ if params.get("risk_class") in {
165
+ "read_only", "mutation", "disclosure",
166
+ }
167
+ else "none"
168
+ )
169
+ return {
170
+ "work_order": order,
171
+ "result_contract": {
172
+ "executor_protocol": "work_order:v1",
173
+ "schema": "ExecutionResultV1",
174
+ "version": 1,
175
+ "work_order_id": params.get("work_order_id"),
176
+ "work_order_digest": params.get("work_order_digest"),
177
+ "work_order_version": params.get("version"),
178
+ "required_fields": [
179
+ "run_id", "attempt_number", "terminal_outcome",
180
+ "started_at", "ended_at", "executor_identity",
181
+ "effect_class", "receipt_refs", "summary", "error",
182
+ ],
183
+ "effect_class": effect_class,
184
+ "terminal_outcomes": [
185
+ "succeeded", "failed", "skipped", "cancelled",
186
+ ],
187
+ "verification_note": (
188
+ "Executor verification claims are observational; Colony "
189
+ "requires its configured independent evidence verifier."
190
+ ),
191
+ "complete_body_shape": {
192
+ "claim_attempt_id": "<echo exact claim attempt>",
193
+ "output": {
194
+ "execution_result": {
195
+ "schema": "ExecutionResultV1",
196
+ "version": 1,
197
+ "work_order_id": params.get("work_order_id"),
198
+ "work_order_digest": params.get(
199
+ "work_order_digest"
200
+ ),
201
+ "work_order_version": params.get("version"),
202
+ "run_id": "<executor run id>",
203
+ "attempt_number": "<1-based integer>",
204
+ "terminal_outcome": "<terminal outcome>",
205
+ "started_at": "<ISO-8601>",
206
+ "ended_at": "<ISO-8601>",
207
+ "executor_identity": "<claiming worker node id>",
208
+ "effect_class": effect_class,
209
+ "receipt_refs": ["<real durable evidence ref>"],
210
+ "verification_result": "unverified",
211
+ "summary": "<what actually happened>",
212
+ "error": "",
213
+ },
214
+ },
215
+ },
216
+ },
217
+ }
218
+
219
+
220
+ def load_config() -> Dict[str, Any]:
221
+ """Resolve worker configuration from the environment.
222
+
223
+ Read at call time (not import time) so cron env sourcing and tests
224
+ both behave predictably.
225
+ """
226
+ node_id = os.environ.get("COLONY_WORKER_NODE_ID") or (
227
+ os.environ.get("COLONY_AGENT_NAME", "hermes").strip().lower().replace(" ", "-")
228
+ + "-agent"
229
+ )
230
+ return {
231
+ "colony_url": os.environ.get("COLONY_URL", "http://127.0.0.1:7777"),
232
+ "api_key": os.environ.get("COLONY_API_KEY", "dev-mode-no-key"),
233
+ "webhook_url": os.environ.get(
234
+ "COLONY_JOBS_WEBHOOK_URL", "http://127.0.0.1:8644/webhooks/colony-jobs"
235
+ ),
236
+ "node_id": node_id,
237
+ # How many jobs to hand to the agent per run. Keep small — each
238
+ # one is a full agent invocation.
239
+ "max_jobs": int(os.environ.get("COLONY_WORKER_MAX_JOBS", "1")),
240
+ }
241
+
242
+
243
+ def _headers(cfg: Dict[str, Any]) -> Dict[str, str]:
244
+ return {"X-API-Key": cfg["api_key"], "Content-Type": "application/json"}
245
+
246
+
247
+ def _post(cfg: Dict[str, Any], url: str, body: dict, timeout: int = 15) -> dict:
248
+ req = urllib.request.Request(
249
+ url, data=json.dumps(body).encode("utf-8"), headers=_headers(cfg), method="POST"
250
+ )
251
+ with urllib.request.urlopen(req, timeout=timeout) as resp:
252
+ raw = resp.read().decode("utf-8")
253
+ return json.loads(raw) if raw else {}
254
+
255
+
256
+ def register_worker(cfg: Dict[str, Any]) -> None:
257
+ """Registration is ephemeral (lost on sidecar restart) — re-register every run."""
258
+ capabilities = agent_action_capabilities()
259
+ _post(
260
+ cfg,
261
+ f"{cfg['colony_url']}/v1/host/queue/workers/register",
262
+ {
263
+ "node_id": cfg["node_id"],
264
+ "capabilities": capabilities,
265
+ "job_types": ["agent_action"],
266
+ "max_concurrent": 1,
267
+ "available": True,
268
+ "load": 0.0,
269
+ },
270
+ )
271
+
272
+
273
+ def claim_job(cfg: Dict[str, Any]) -> Optional[dict]:
274
+ capabilities = agent_action_capabilities()
275
+ return _post(
276
+ cfg,
277
+ f"{cfg['colony_url']}/v1/host/queue/jobs/claim",
278
+ {
279
+ "node_id": cfg["node_id"],
280
+ "capabilities": capabilities,
281
+ "job_types": ["agent_action"],
282
+ "max_concurrent": 1,
283
+ },
284
+ ) or None
285
+
286
+
287
+ def start_job(
288
+ cfg: Dict[str, Any], job_id: str, claim_attempt_id: Optional[str],
289
+ ) -> bool:
290
+ response = _post(
291
+ cfg,
292
+ f"{cfg['colony_url']}/v1/host/queue/jobs/{job_id}/start",
293
+ {"claim_attempt_id": claim_attempt_id},
294
+ )
295
+ return isinstance(response, dict) and response.get("success") is True
296
+
297
+
298
+ def release_job(
299
+ cfg: Dict[str, Any], job_id: str, claim_attempt_id: Optional[str],
300
+ ) -> None:
301
+ _post(
302
+ cfg,
303
+ f"{cfg['colony_url']}/v1/host/queue/jobs/{job_id}/release",
304
+ {"claim_attempt_id": claim_attempt_id},
305
+ )
306
+
307
+
308
+ def build_webhook_payload(cfg: Dict[str, Any], job: dict) -> dict:
309
+ """Render the agent-webhook payload for a claimed job (pure — testable)."""
310
+ job_id = job.get("job_id") or job.get("id")
311
+ claim_attempt_id = job.get("claim_attempt_id")
312
+ params = job.get("payload") or job.get("params") or {}
313
+ colony_url = cfg["colony_url"]
314
+ return {
315
+ "type": "agent_job",
316
+ "occurred_at": datetime.now(timezone.utc).isoformat(),
317
+ "payload": {
318
+ "job_id": job_id,
319
+ "claim_attempt_id": claim_attempt_id,
320
+ "action_hint": params.get("action_hint", ""),
321
+ "domain": params.get("domain", ""),
322
+ "risk": params.get("risk", ""),
323
+ "description": params.get("description", ""),
324
+ "context": params.get("context", {}),
325
+ "report_example": params.get("report_example", {}),
326
+ **work_order_webhook_fields(params),
327
+ "colony_url": colony_url,
328
+ "observations_url": f"{colony_url}/v1/host/observations",
329
+ "heartbeat_url": f"{colony_url}/v1/host/queue/jobs/{job_id}/heartbeat",
330
+ "complete_url": f"{colony_url}/v1/host/queue/jobs/{job_id}/complete",
331
+ "fail_url": f"{colony_url}/v1/host/queue/jobs/{job_id}/fail",
332
+ "api_key_header": "X-API-Key",
333
+ },
334
+ }
335
+
336
+
337
+ def fire_to_agent(cfg: Dict[str, Any], job: dict) -> bool:
338
+ """Hand the claimed job to the agent via the jobs webhook.
339
+
340
+ The webhook route's prompt template renders these fields; the agent
341
+ decides how to execute with its own toolsets and closes the job
342
+ lifecycle itself via the URLs in the payload.
343
+ """
344
+ job_id = job.get("job_id") or job.get("id")
345
+ claim_attempt_id = job.get("claim_attempt_id")
346
+ payload = build_webhook_payload(cfg, job)
347
+ try:
348
+ body, headers = encode_hermes_webhook(payload)
349
+ req = urllib.request.Request(
350
+ cfg["webhook_url"],
351
+ data=body,
352
+ headers=headers,
353
+ method="POST",
354
+ )
355
+ urllib.request.urlopen(req, timeout=15)
356
+ return True
357
+ except Exception as exc:
358
+ print(f"Webhook fire failed for job {job_id}: {exc}")
359
+ # Release the claim so another run can retry
360
+ try:
361
+ _post(
362
+ cfg,
363
+ f"{cfg['colony_url']}/v1/host/queue/jobs/{job_id}/release",
364
+ {"claim_attempt_id": claim_attempt_id},
365
+ )
366
+ except Exception:
367
+ pass
368
+ return False
369
+
370
+
371
+ def run(cfg: Dict[str, Any]) -> int:
372
+ """One cron tick: register, claim up to max_jobs, hand each to the agent."""
373
+ if os.environ.get(
374
+ "COLONY_AGENT_JOB_CLAIMS_ENABLED", "true"
375
+ ).strip().lower() not in {"1", "true", "yes", "on"}:
376
+ print("Agent job claims disabled; initiative forwarding is unaffected.")
377
+ return 0
378
+ try:
379
+ register_worker(cfg)
380
+ except Exception as exc:
381
+ print(f"Worker registration failed (sidecar down?): {exc}")
382
+ return 0
383
+
384
+ handed_off = 0
385
+ for _ in range(cfg["max_jobs"]):
386
+ try:
387
+ job = claim_job(cfg)
388
+ except Exception as exc:
389
+ print(f"Claim failed: {exc}")
390
+ break
391
+ if not job:
392
+ break
393
+ job_id = job.get("job_id") or job.get("id")
394
+ hint = (job.get("payload") or {}).get("action_hint", "?")
395
+ try:
396
+ claim_attempt_id = job.get("claim_attempt_id")
397
+ if not start_job(cfg, str(job_id), claim_attempt_id):
398
+ raise RuntimeError("start transition was not accepted")
399
+ except Exception as exc:
400
+ print(f"Start failed for job {job_id}: {exc}")
401
+ try:
402
+ release_job(cfg, str(job_id), claim_attempt_id)
403
+ except Exception:
404
+ pass
405
+ continue
406
+ if fire_to_agent(cfg, job):
407
+ handed_off += 1
408
+ print(f"Handed job {job_id} ({hint}) to the agent")
409
+
410
+ if not handed_off:
411
+ print("No pending agent_action jobs.")
412
+ return handed_off
413
+
414
+
415
+ def main(argv: Optional[list] = None) -> int:
416
+ parser = argparse.ArgumentParser(
417
+ prog="colony-queue-worker",
418
+ description="Claim Colony agent_action jobs and hand them to the agent webhook.",
419
+ )
420
+ parser.add_argument(
421
+ "--dry-run",
422
+ action="store_true",
423
+ help="print the resolved configuration and exit without any network calls",
424
+ )
425
+ args = parser.parse_args(argv)
426
+
427
+ cfg = load_config()
428
+ if args.dry_run:
429
+ print("colony-queue-worker (dry run — no network calls):")
430
+ print(f" colony_url: {cfg['colony_url']}")
431
+ print(f" webhook_url: {cfg['webhook_url']}")
432
+ print(f" node_id: {cfg['node_id']}")
433
+ print(f" max_jobs: {cfg['max_jobs']}")
434
+ return 0
435
+
436
+ run(cfg)
437
+ return 0
438
+
439
+
440
+ if __name__ == "__main__":
441
+ raise SystemExit(main())
@@ -0,0 +1,152 @@
1
+ """Report the agent's skill index to Colony.
2
+
3
+ Installed as the ``colony-skills-sync`` console script (v0.20.0); the
4
+ logic moved here unchanged from
5
+ ``plugins/hermes-plugin/poller/colony-skills-sync.py`` (v0.18.0),
6
+ which remains as a thin back-compat wrapper.
7
+
8
+ Scans the Hermes skills directory for SKILL.md files, parses the
9
+ frontmatter (name / description / tags), and POSTs the index to
10
+ Colony's push-only "skills" observation domain. Colony's self-directed
11
+ thinking and capability-gap machinery read from there, so Colony
12
+ proposes work the agent can actually do.
13
+
14
+ Run from cron daily (the wizard installs ``0 9 * * *``) or after
15
+ installing new skills. The TypeScript OpenClaw plugin ships the same
16
+ sync built-in (src/hermes-skills.ts); this worker is for deployments
17
+ using the Python Hermes plugin.
18
+
19
+ Environment (unchanged from the v0.18 script):
20
+ COLONY_URL sidecar URL (default http://127.0.0.1:7777)
21
+ COLONY_API_KEY API key (default dev-mode-no-key)
22
+ HERMES_SKILLS_DIR skills tree (default ~/.hermes/skills)
23
+
24
+ Stdlib-only on purpose — must run from cron without the sidecar deps.
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import argparse
30
+ import json
31
+ import os
32
+ import pathlib
33
+ import re
34
+ import urllib.request
35
+ from typing import Optional
36
+
37
+ MAX_DEPTH = 4
38
+
39
+
40
+ def skills_dir() -> pathlib.Path:
41
+ """Resolve the skills directory from the environment at call time."""
42
+ return pathlib.Path(
43
+ os.environ.get("HERMES_SKILLS_DIR", "~/.hermes/skills")
44
+ ).expanduser()
45
+
46
+
47
+ def _parse_frontmatter(text: str) -> dict:
48
+ """Minimal SKILL.md frontmatter parse — name/description scalars and
49
+ tags (inline ``[a, b]`` or block list), no YAML dependency."""
50
+ match = re.match(r"\A---\s*\n(.*?)\n---", text, re.DOTALL)
51
+ if not match:
52
+ return {}
53
+ fm = match.group(1)
54
+ out: dict = {}
55
+ name = re.search(r"^name:\s*[\"']?([^\"'\n]+)", fm, re.MULTILINE)
56
+ desc = re.search(r"^description:\s*[\"']?([^\"\n]+?)[\"']?\s*$",
57
+ fm, re.MULTILINE)
58
+ if name:
59
+ out["name"] = name.group(1).strip()
60
+ if desc:
61
+ out["description"] = desc.group(1).strip()
62
+ inline = re.search(r"^\s*tags:\s*\[([^\]]*)\]", fm, re.MULTILINE)
63
+ if inline:
64
+ out["tags"] = [t.strip().strip("\"'")
65
+ for t in inline.group(1).split(",") if t.strip()]
66
+ else:
67
+ block = re.search(r"^\s*tags:\s*\n((?:\s+-\s+.*\n?)+)", fm,
68
+ re.MULTILINE)
69
+ if block:
70
+ out["tags"] = [ln.split("-", 1)[1].strip().strip("\"'")
71
+ for ln in block.group(1).splitlines()
72
+ if "-" in ln]
73
+ return out
74
+
75
+
76
+ def scan(base: Optional[pathlib.Path] = None) -> list:
77
+ """Scan the skills tree, returning observation dicts for each SKILL.md."""
78
+ base = base if base is not None else skills_dir()
79
+ observations = []
80
+ if not base.is_dir():
81
+ return observations
82
+ for skill_md in sorted(base.rglob("SKILL.md")):
83
+ rel = skill_md.relative_to(base)
84
+ if len(rel.parts) > MAX_DEPTH:
85
+ continue
86
+ try:
87
+ meta = _parse_frontmatter(
88
+ skill_md.read_text(encoding="utf-8", errors="replace"))
89
+ except OSError:
90
+ continue
91
+ name = meta.get("name") or skill_md.parent.name
92
+ observations.append({
93
+ "entity_id": name,
94
+ "payload": {
95
+ "description": meta.get("description", ""),
96
+ "tags": meta.get("tags", []),
97
+ "path": str(skill_md),
98
+ "source": "hermes",
99
+ },
100
+ })
101
+ return observations
102
+
103
+
104
+ def report(observations: list) -> int:
105
+ """POST the skill index to Colony's skills observation domain.
106
+
107
+ Returns the HTTP status code.
108
+ """
109
+ colony_url = os.environ.get("COLONY_URL", "http://127.0.0.1:7777")
110
+ api_key = os.environ.get("COLONY_API_KEY", "dev-mode-no-key")
111
+ body = {"domain": "skills", "reported_by": "hermes-skills-sync",
112
+ "observations": observations}
113
+ req = urllib.request.Request(
114
+ f"{colony_url}/v1/host/observations",
115
+ data=json.dumps(body).encode("utf-8"),
116
+ headers={"X-API-Key": api_key, "Content-Type": "application/json"},
117
+ method="POST")
118
+ with urllib.request.urlopen(req, timeout=30) as resp:
119
+ return resp.status
120
+
121
+
122
+ def main(argv: Optional[list] = None) -> int:
123
+ parser = argparse.ArgumentParser(
124
+ prog="colony-skills-sync",
125
+ description="Report the agent's installed skill index to Colony.",
126
+ )
127
+ parser.add_argument(
128
+ "--dry-run",
129
+ action="store_true",
130
+ help="scan and print what would be reported without POSTing to Colony",
131
+ )
132
+ args = parser.parse_args(argv)
133
+
134
+ base = skills_dir()
135
+ observations = scan(base)
136
+ if not observations:
137
+ print(f"No skills found under {base}")
138
+ return 0
139
+ if args.dry_run:
140
+ print("colony-skills-sync (dry run — nothing reported):")
141
+ for obs in observations:
142
+ print(f" - {obs['entity_id']}: {obs['payload'].get('description', '')}")
143
+ print(f"Would report {len(observations)} skills from {base}")
144
+ return 0
145
+
146
+ status = report(observations)
147
+ print(f"Reported {len(observations)} skills (HTTP {status}) from {base}")
148
+ return 0
149
+
150
+
151
+ if __name__ == "__main__":
152
+ raise SystemExit(main())
@@ -0,0 +1,71 @@
1
+ """Colony World Model — persistent, structured entity graph.
2
+
3
+ Provides seven entity types (Person, Company, Project, Product, Location,
4
+ Event, Concept), entity extraction, resolution/deduplication, and graph
5
+ traversal. Backed by SQLite (default) or Neo4j.
6
+
7
+ Quick start::
8
+
9
+ from apsimo.world_model import WorldModelStore, WorldModelConfig
10
+
11
+ config = WorldModelConfig(backend="sqlite", sqlite_path=":memory:")
12
+ async with WorldModelStore(config) as store:
13
+ entity = await store.upsert_entity(PersonEntity(
14
+ id="we-000-test",
15
+ name="Alice Chen",
16
+ entity_type="person",
17
+ confidence=0.8,
18
+ ))
19
+ result = await store.find_entities("Alice")
20
+ """
21
+
22
+ from .store import WorldModelStore, GraphNeighborhoodResult, WorldModelStats
23
+ from .config import WorldModelConfig
24
+ from .entities import (
25
+ BaseEntity,
26
+ PersonEntity,
27
+ CompanyEntity,
28
+ ProjectEntity,
29
+ ProductEntity,
30
+ LocationEntity,
31
+ EventEntity,
32
+ ConceptEntity,
33
+ ENTITY_CLASS_MAP,
34
+ entity_from_dict,
35
+ )
36
+ from .relationships import WorldRelationship
37
+ from .constants import ENTITY_TYPES, RELATIONSHIP_TYPES, EXTERNAL_ID_KEYS
38
+ from .confidence import (
39
+ CONFIDENCE_BY_SOURCE,
40
+ compute_property_confidence,
41
+ boost_confidence,
42
+ )
43
+
44
+ __all__ = [
45
+ # Store
46
+ "WorldModelStore",
47
+ "GraphNeighborhoodResult",
48
+ "WorldModelStats",
49
+ "WorldModelConfig",
50
+ # Entities
51
+ "BaseEntity",
52
+ "PersonEntity",
53
+ "CompanyEntity",
54
+ "ProjectEntity",
55
+ "ProductEntity",
56
+ "LocationEntity",
57
+ "EventEntity",
58
+ "ConceptEntity",
59
+ "ENTITY_CLASS_MAP",
60
+ "entity_from_dict",
61
+ # Relationships
62
+ "WorldRelationship",
63
+ # Constants
64
+ "ENTITY_TYPES",
65
+ "RELATIONSHIP_TYPES",
66
+ "EXTERNAL_ID_KEYS",
67
+ # Confidence
68
+ "CONFIDENCE_BY_SOURCE",
69
+ "compute_property_confidence",
70
+ "boost_confidence",
71
+ ]