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,12 @@
1
+ """Proposals: well-formed findings/suggestions delivered to the owner via the
2
+ guarded (shadow-gated, boundary-checked, rate-limited) reach-out path."""
3
+
4
+ from apsimo.proposals.models import Proposal, ProposalStore
5
+ from apsimo.proposals.engine import (
6
+ build_from_thinker, build_from_research, proposal_to_payload,
7
+ )
8
+
9
+ __all__ = [
10
+ "Proposal", "ProposalStore",
11
+ "build_from_thinker", "build_from_research", "proposal_to_payload",
12
+ ]
@@ -0,0 +1,114 @@
1
+ """Turn self-directed thoughts and research findings into Proposals."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from datetime import datetime, timezone
7
+ from typing import Any, Dict, Optional
8
+
9
+ from apsimo.proposals.models import Proposal
10
+
11
+ _THINK_PREFIX = re.compile(r"^\[self-directed thinking\]\s*", re.IGNORECASE)
12
+
13
+ # Ungrounded rationale text: empty, or a generic "worth doing" placeholder
14
+ # that carries no evidence of WHY the work helps. Proposals whose only
15
+ # justification is one of these do not ship (honest why_it_helps: item 4).
16
+ _UNGROUNDED = re.compile(
17
+ r"^(i think this work is worth doing( now)?\.?"
18
+ r"|worth doing( now)?\.?"
19
+ r"|advances your priorities\.?"
20
+ r"|moves a piece of your work forward\.?)$",
21
+ re.IGNORECASE,
22
+ )
23
+
24
+
25
+ def _first_sentence(text: str, limit: int = 200) -> str:
26
+ text = (text or "").strip()
27
+ if not text:
28
+ return ""
29
+ m = re.search(r"[.!?](\s|$)", text)
30
+ sentence = text[: m.end()].strip() if m else text
31
+ return sentence[:limit].strip()
32
+
33
+
34
+ def build_from_thinker(initiative: Any) -> Optional[Proposal]:
35
+ """Package one self-directed-thinking initiative as a Proposal.
36
+
37
+ Returns None (does NOT ship) when the initiative carries no grounded
38
+ reason: ``why_it_helps`` must come from the initiative's own evidence
39
+ (its rationale), never a per-type template. A thought whose rationale is
40
+ empty or a generic "worth doing" placeholder is not deliverable.
41
+ """
42
+ title = (getattr(initiative, "description", "") or "").strip()
43
+ itype = getattr(initiative, "type", None)
44
+ itype = getattr(itype, "value", None) or str(itype or "research")
45
+ rationale = _THINK_PREFIX.sub("", getattr(initiative, "rationale", "") or "").strip()
46
+
47
+ # Grounding gate: a real, evidence-bearing rationale is required.
48
+ if not rationale or _UNGROUNDED.match(rationale):
49
+ return None
50
+
51
+ try:
52
+ conf = float(getattr(initiative, "priority", 0.6) or 0.6)
53
+ except (TypeError, ValueError):
54
+ conf = 0.6
55
+ return Proposal(
56
+ title=title[:100] or "(proposal)",
57
+ finding=rationale,
58
+ # Grounded in the initiative's own evidence, not a template.
59
+ why_it_helps=_first_sentence(rationale),
60
+ suggested_action=title,
61
+ citations=[],
62
+ source="thinker",
63
+ initiative_type=itype,
64
+ confidence=conf,
65
+ )
66
+
67
+
68
+ def build_from_research(goal: str, artifact_text: str, sources: list,
69
+ confidence: float = 0.7) -> Optional[Proposal]:
70
+ """Package a research finding (with citations) as a Proposal.
71
+
72
+ Returns None (does NOT ship) without grounded evidence: a research
73
+ proposal needs an actual finding AND the question that motivated it (its
74
+ grounded ``why_it_helps``). An empty finding or a missing goal means there
75
+ is nothing honest to say about why it helps.
76
+ """
77
+ finding = (artifact_text or "").strip()
78
+ goal = (goal or "").strip()
79
+ if not finding or not goal:
80
+ return None
81
+ cites = []
82
+ for s in (sources or [])[:6]:
83
+ if isinstance(s, dict):
84
+ cites.append({"title": s.get("title", ""), "url": s.get("url", "")})
85
+ else:
86
+ cites.append({"title": str(getattr(s, "title", "") or ""),
87
+ "url": str(getattr(s, "url", "") or "")})
88
+ return Proposal(
89
+ title=goal[:100],
90
+ finding=finding[:1200],
91
+ # Grounded in the actual question that prompted the research.
92
+ why_it_helps=f"answers a question you're working on: {goal}"[:200],
93
+ suggested_action="Review the finding and tell me if you want me to go deeper.",
94
+ citations=cites, source="research", initiative_type="research",
95
+ confidence=confidence,
96
+ )
97
+
98
+
99
+ def proposal_to_payload(p: Proposal) -> Dict[str, Any]:
100
+ """Delivery payload for a Proposal (dedicated 'proposal' type)."""
101
+ return {
102
+ "id": p.id,
103
+ "type": "proposal",
104
+ "priority": p.confidence,
105
+ "title": p.title[:80],
106
+ "description": p.render(),
107
+ "rationale": p.finding,
108
+ "suggested_action": p.suggested_action,
109
+ "entity_id": None, # proposals target the owner
110
+ "entity_type": "proposal",
111
+ "channel_hint": "dm",
112
+ "context": {},
113
+ "generated_at": datetime.now(timezone.utc).isoformat(),
114
+ }
@@ -0,0 +1,207 @@
1
+ """Proposal artifact + store.
2
+
3
+ A Proposal is a well-formed thing Colony wants to put in front of the owner:
4
+ a finding (what it noticed / learned), why it helps him, a concrete suggested
5
+ action, and citations. It is a DEDICATED type, distinct from routine reach-out
6
+ initiatives, delivered through the same guarded (shadow-gated, boundary-checked,
7
+ rate-limited) path.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import sqlite3
14
+ import threading
15
+ import time
16
+ import uuid
17
+ from dataclasses import dataclass, field
18
+ from typing import Any, Dict, List, Optional
19
+
20
+
21
+ @dataclass
22
+ class Proposal:
23
+ title: str
24
+ finding: str = "" # what Colony noticed / learned
25
+ why_it_helps: str = "" # relevance to the owner
26
+ suggested_action: str = "" # concrete next step
27
+ citations: List[Dict[str, str]] = field(default_factory=list) # [{title,url}]
28
+ source: str = "thinker" # thinker | research | <initiative_id>
29
+ initiative_type: str = "research"
30
+ confidence: float = 0.6
31
+ status: str = "shadow" # shadow | delivered | dismissed | draft
32
+ id: str = field(default_factory=lambda: f"prop-{uuid.uuid4().hex[:12]}")
33
+ created_at: float = field(default_factory=time.time)
34
+ route_ref: str = ""
35
+ result_ref: str = ""
36
+ subject_person_id: str = ""
37
+ viewer_scope: str = "owner"
38
+ shareability: str = "owner_private"
39
+ scope_digest: str = ""
40
+
41
+ def render(self) -> str:
42
+ """Owner-facing text handed to the composing agent."""
43
+ lines = [self.title.strip()]
44
+ finding = self.finding.strip()
45
+ why = self.why_it_helps.strip()
46
+ if finding:
47
+ lines.append(f"What I found: {finding}")
48
+ # Skip the why-line when it merely restates the finding (the grounded
49
+ # why is often the finding's lead sentence) — no honest information is
50
+ # lost and the message stays tight.
51
+ if why and not (finding and finding.startswith(why)):
52
+ lines.append(f"Why it helps you: {why}")
53
+ if self.suggested_action:
54
+ lines.append(f"Suggested next step: {self.suggested_action.strip()}")
55
+ if self.citations:
56
+ cites = "; ".join(
57
+ (c.get("title") or c.get("url") or "").strip()
58
+ for c in self.citations if (c.get("title") or c.get("url"))
59
+ )
60
+ if cites:
61
+ lines.append(f"Sources: {cites}")
62
+ return "\n".join(lines)
63
+
64
+ def to_row(self) -> Dict[str, Any]:
65
+ return {
66
+ "id": self.id, "title": self.title, "finding": self.finding,
67
+ "why_it_helps": self.why_it_helps, "suggested_action": self.suggested_action,
68
+ "citations": json.dumps(self.citations), "source": self.source,
69
+ "initiative_type": self.initiative_type, "confidence": self.confidence,
70
+ "status": self.status, "created_at": self.created_at,
71
+ "route_ref": self.route_ref, "result_ref": self.result_ref,
72
+ "subject_person_id": self.subject_person_id,
73
+ "viewer_scope": self.viewer_scope,
74
+ "shareability": self.shareability,
75
+ "scope_digest": self.scope_digest,
76
+ }
77
+
78
+ def visible_to(
79
+ self,
80
+ *,
81
+ viewer_person_id: str,
82
+ owner_person_id: str,
83
+ audiences: set[str] | frozenset[str] = frozenset(),
84
+ ) -> bool:
85
+ viewer = str(viewer_person_id or "").strip()
86
+ if not viewer:
87
+ return False
88
+ if viewer == str(owner_person_id or "").strip():
89
+ return True
90
+ if self.shareability == "public":
91
+ return "global" in audiences
92
+ if self.shareability == "shared":
93
+ return "shared" in audiences
94
+ if self.shareability == "subject_private":
95
+ return viewer == self.subject_person_id
96
+ return False
97
+
98
+ @classmethod
99
+ def from_row(cls, r: Dict[str, Any]) -> "Proposal":
100
+ try:
101
+ cites = json.loads(r.get("citations") or "[]")
102
+ except Exception:
103
+ cites = []
104
+ return cls(
105
+ id=r["id"], title=r["title"], finding=r.get("finding", "") or "",
106
+ why_it_helps=r.get("why_it_helps", "") or "",
107
+ suggested_action=r.get("suggested_action", "") or "",
108
+ citations=cites, source=r.get("source", "thinker") or "thinker",
109
+ initiative_type=r.get("initiative_type", "research") or "research",
110
+ confidence=float(r.get("confidence", 0.6) or 0.6),
111
+ status=r.get("status", "shadow") or "shadow",
112
+ created_at=float(r.get("created_at") or time.time()),
113
+ route_ref=r.get("route_ref", "") or "",
114
+ result_ref=r.get("result_ref", "") or "",
115
+ subject_person_id=r.get("subject_person_id", "") or "",
116
+ viewer_scope=r.get("viewer_scope", "owner") or "owner",
117
+ shareability=r.get("shareability", "owner_private") or "owner_private",
118
+ scope_digest=r.get("scope_digest", "") or "",
119
+ )
120
+
121
+
122
+ class ProposalStore:
123
+ def __init__(self, db_path: Optional[str] = None) -> None:
124
+ self._lock = threading.RLock()
125
+ self._conn = sqlite3.connect(str(db_path) if db_path else ":memory:",
126
+ check_same_thread=False)
127
+ self._conn.row_factory = sqlite3.Row
128
+ with self._lock:
129
+ self._conn.execute(
130
+ """CREATE TABLE IF NOT EXISTS proposals (
131
+ id TEXT PRIMARY KEY, title TEXT NOT NULL, finding TEXT,
132
+ why_it_helps TEXT, suggested_action TEXT, citations TEXT,
133
+ source TEXT, initiative_type TEXT, confidence REAL,
134
+ status TEXT, created_at REAL, route_ref TEXT,
135
+ result_ref TEXT, subject_person_id TEXT,
136
+ viewer_scope TEXT DEFAULT 'owner',
137
+ shareability TEXT DEFAULT 'owner_private', scope_digest TEXT
138
+ )""")
139
+ columns = {
140
+ row[1] for row in self._conn.execute(
141
+ "PRAGMA table_info(proposals)"
142
+ ).fetchall()
143
+ }
144
+ for name, declaration in (
145
+ ("route_ref", "TEXT"),
146
+ ("result_ref", "TEXT"),
147
+ ("subject_person_id", "TEXT"),
148
+ ("viewer_scope", "TEXT DEFAULT 'owner'"),
149
+ ("shareability", "TEXT DEFAULT 'owner_private'"),
150
+ ("scope_digest", "TEXT"),
151
+ ):
152
+ if name not in columns:
153
+ self._conn.execute(
154
+ f"ALTER TABLE proposals ADD COLUMN {name} {declaration}"
155
+ )
156
+ self._conn.commit()
157
+
158
+ def add(self, p: Proposal) -> Proposal:
159
+ row = p.to_row()
160
+ with self._lock:
161
+ cols = ", ".join(row); ph = ", ".join(["?"] * len(row))
162
+ self._conn.execute(
163
+ f"INSERT OR REPLACE INTO proposals ({cols}) VALUES ({ph})",
164
+ list(row.values()))
165
+ self._conn.commit()
166
+ return p
167
+
168
+ def add_if_absent(self, p: Proposal) -> bool:
169
+ """Insert a stable proposal without overwriting operator state."""
170
+
171
+ row = p.to_row()
172
+ with self._lock:
173
+ cols = ", ".join(row)
174
+ ph = ", ".join(["?"] * len(row))
175
+ cursor = self._conn.execute(
176
+ f"INSERT OR IGNORE INTO proposals ({cols}) VALUES ({ph})",
177
+ list(row.values()),
178
+ )
179
+ self._conn.commit()
180
+ return cursor.rowcount == 1
181
+
182
+ def list(self, status: Optional[str] = None, limit: int = 50) -> List[Proposal]:
183
+ q = "SELECT * FROM proposals"
184
+ params: List[Any] = []
185
+ if status:
186
+ q += " WHERE status=?"; params.append(status)
187
+ q += " ORDER BY created_at DESC LIMIT ?"; params.append(limit)
188
+ with self._lock:
189
+ rows = self._conn.execute(q, params).fetchall()
190
+ return [Proposal.from_row(dict(r)) for r in rows]
191
+
192
+ def get(self, proposal_id: str) -> Optional[Proposal]:
193
+ with self._lock:
194
+ row = self._conn.execute(
195
+ "SELECT * FROM proposals WHERE id=?", (proposal_id,),
196
+ ).fetchone()
197
+ return Proposal.from_row(dict(row)) if row is not None else None
198
+
199
+ def set_status(self, proposal_id: str, status: str) -> bool:
200
+ with self._lock:
201
+ cur = self._conn.execute(
202
+ "UPDATE proposals SET status=? WHERE id=?", (status, proposal_id))
203
+ self._conn.commit()
204
+ return cur.rowcount > 0
205
+
206
+ def count(self, status: Optional[str] = None) -> int:
207
+ return len(self.list(status=status, limit=100000))
@@ -0,0 +1 @@
1
+ """Opt-in, finite qualification through existing model consumers."""
@@ -0,0 +1,75 @@
1
+ """Small neutral cases. A role completion is not native agent qualification."""
2
+ import json
3
+
4
+ from .records import CaseSpec
5
+
6
+
7
+ async def role_completion(inputs, context):
8
+ response = await context.router.complete(inputs['messages'], context={
9
+ 'function_role': inputs['role'], 'allow_fallback': False,
10
+ 'max_output_tokens': inputs.get('max_output_tokens', 512)})
11
+ return {'output': response.content, 'effects': {}}
12
+
13
+
14
+ def json_fields(observed, oracle):
15
+ """Exact independently specified fields, not a model judging itself."""
16
+ output = observed.get('output')
17
+ if isinstance(output, str):
18
+ try:
19
+ output = json.loads(output)
20
+ except (ValueError, TypeError):
21
+ return {'output_is_json': False}
22
+ root = {**observed, 'output': output}
23
+ checks = {}
24
+ for item in oracle['fields']:
25
+ current = root
26
+ try:
27
+ for part in item['path']:
28
+ current = current[part]
29
+ except (KeyError, IndexError, TypeError):
30
+ checks[item['name']] = False
31
+ else:
32
+ checks[item['name']] = type(current) is type(item['equals']) and current == item['equals']
33
+ return checks
34
+
35
+
36
+ STANDARD = [
37
+ CaseSpec(id='chat.grounded-note', version='1', role='chat', boundary='role_completion',
38
+ consumer='role_completion', evaluator='json_fields',
39
+ inputs={'role': 'chat', 'messages': [
40
+ {'role': 'system', 'content': 'Answer from the supplied note only. Return a JSON object; use null for information absent from the note.'},
41
+ {'role': 'user', 'content': 'Note: The blue sample case is in drawer 4. The silver case was moved, but its new location is unknown. Where is each case? Use keys blue and silver.'}]},
42
+ oracle={'fields': [
43
+ {'name': 'known_location', 'path': ['output', 'blue'], 'equals': 'drawer 4'},
44
+ {'name': 'unknown_preserved', 'path': ['output', 'silver'], 'equals': None}]}),
45
+ CaseSpec(id='extraction.conditions', version='1', role='extraction', boundary='role_completion',
46
+ consumer='role_completion', evaluator='json_fields',
47
+ inputs={'role': 'extraction', 'messages': [
48
+ {'role': 'system', 'content': 'Extract only explicit information. Return JSON with keys item, location, valid_day, requires_wet_shelf (boolean), owner. Use null for absent information.'},
49
+ {'role': 'user', 'content': 'For tomorrow only, put the blue sample case in drawer 4 if the shelf is wet. Nobody has identified its owner.'}]},
50
+ oracle={'fields': [
51
+ {'name': 'item', 'path': ['output', 'item'], 'equals': 'blue sample case'},
52
+ {'name': 'location', 'path': ['output', 'location'], 'equals': 'drawer 4'},
53
+ {'name': 'time_condition', 'path': ['output', 'valid_day'], 'equals': 'tomorrow'},
54
+ {'name': 'wet_shelf_condition', 'path': ['output', 'requires_wet_shelf'], 'equals': True},
55
+ {'name': 'unknown_owner', 'path': ['output', 'owner'], 'equals': None}]}),
56
+ ]
57
+
58
+ CONSUMERS = {'role_completion': role_completion}
59
+ EVALUATORS = {'json_fields': json_fields}
60
+
61
+ from .memory_cases import CASES as MEMORY_CASES, CONSUMERS as MEMORY_CONSUMERS, EVALUATORS as MEMORY_EVALUATORS
62
+ STANDARD.extend(MEMORY_CASES)
63
+ CONSUMERS.update(MEMORY_CONSUMERS)
64
+ EVALUATORS.update(MEMORY_EVALUATORS)
65
+
66
+ from .structured_cases import CASES as STRUCTURED_CASES
67
+ STANDARD.extend(STRUCTURED_CASES)
68
+
69
+
70
+ def select_cases(roles):
71
+ cases = [case for case in STANDARD if case.role in roles]
72
+ uncovered = set(roles) - {case.role for case in cases}
73
+ if uncovered:
74
+ raise ValueError('No installed standard cases for roles: ' + ', '.join(sorted(uncovered)))
75
+ return cases
@@ -0,0 +1,51 @@
1
+ """Opt-in CLI. Inspect/compare are offline; evaluate invokes selected consumers."""
2
+ import asyncio
3
+ import json
4
+ from pathlib import Path
5
+
6
+
7
+ def add_parser(sub):
8
+ parser = sub.add_parser('models', help='Inspect and qualify model bindings without selecting a deployment')
9
+ commands = parser.add_subparsers(dest='models_command', required=True)
10
+ for command in ('inspect', 'evaluate'):
11
+ item = commands.add_parser(command)
12
+ item.add_argument('binding', help='Existing modelPool or named tier binding')
13
+ item.add_argument('--config', required=True, type=Path, help='Existing private host model configuration JSON')
14
+ if command == 'evaluate':
15
+ item.add_argument('--roles', default='chat,extraction')
16
+ item.add_argument('--suite', choices=['standard'], default='standard')
17
+ item.add_argument('--evidence-mode', choices=['actual_inference', 'controlled'], default='actual_inference',
18
+ help='Label controlled fixtures separately; neither label attests serving weights')
19
+ item.add_argument('--output', required=True, type=Path, help='New private result directory')
20
+ item.add_argument('--resume', action='store_true', help='Continue untouched cases; interrupted attempts are never rerun')
21
+ item = commands.add_parser('compare')
22
+ item.add_argument('incumbent', type=Path)
23
+ item.add_argument('candidate', type=Path)
24
+ item.add_argument('--json', action='store_true')
25
+
26
+
27
+ def run(args):
28
+ from .records import read, write_once, publish
29
+ from .report import compare, summarize, markdown
30
+ if args.models_command == 'compare':
31
+ report = compare(args.incumbent, args.candidate)
32
+ print(json.dumps(report, indent=2) if args.json else markdown(report))
33
+ return 0
34
+ from .runner import inspect_binding, router_for, evaluate
35
+ config = read(args.config)
36
+ recipe = inspect_binding(config, args.binding)
37
+ if args.models_command == 'inspect':
38
+ print(json.dumps(recipe, indent=2))
39
+ return 0
40
+ from .cases import select_cases, CONSUMERS, EVALUATORS
41
+ cases = select_cases([r.strip() for r in args.roles.split(',') if r.strip()])
42
+ asyncio.run(evaluate(args.output, recipe, cases, CONSUMERS, EVALUATORS,
43
+ lambda case: router_for(config, args.binding, [case]), resume=args.resume, evidence_mode=args.evidence_mode))
44
+ report = summarize(args.output)
45
+ # Reports are new immutable views. Earlier reports remain useful when a run resumes.
46
+ index = len(list(args.output.glob('report-*.json'))) + 1
47
+ write_once(args.output / f'report-{index:03d}.json', report)
48
+ text = markdown(report)
49
+ publish(args.output / f'report-{index:03d}.md', text.encode())
50
+ print(text)
51
+ return 0 if all(row['outcome'] == 'pass' for row in report['cases']) else 1