ciris-agent 1.7.7__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 (986) hide show
  1. ciris_adapters/README.md +113 -0
  2. ciris_adapters/__init__.py +30 -0
  3. ciris_adapters/ciris_covenant_metrics/README.md +144 -0
  4. ciris_adapters/ciris_covenant_metrics/__init__.py +36 -0
  5. ciris_adapters/ciris_covenant_metrics/adapter.py +249 -0
  6. ciris_adapters/ciris_covenant_metrics/manifest.json +152 -0
  7. ciris_adapters/ciris_covenant_metrics/services.py +403 -0
  8. ciris_adapters/ciris_hosted_tools/__init__.py +24 -0
  9. ciris_adapters/ciris_hosted_tools/adapter.py +169 -0
  10. ciris_adapters/ciris_hosted_tools/manifest.json +94 -0
  11. ciris_adapters/ciris_hosted_tools/services.py +744 -0
  12. ciris_adapters/external_data_sql/README.md +559 -0
  13. ciris_adapters/external_data_sql/__init__.py +43 -0
  14. ciris_adapters/external_data_sql/adapter.py +144 -0
  15. ciris_adapters/external_data_sql/configurable.py +315 -0
  16. ciris_adapters/external_data_sql/dialects/__init__.py +37 -0
  17. ciris_adapters/external_data_sql/dialects/base.py +133 -0
  18. ciris_adapters/external_data_sql/dialects/mysql.py +63 -0
  19. ciris_adapters/external_data_sql/dialects/postgresql.py +59 -0
  20. ciris_adapters/external_data_sql/dialects/sqlite.py +62 -0
  21. ciris_adapters/external_data_sql/example_config.json +88 -0
  22. ciris_adapters/external_data_sql/example_privacy_schema.yaml +127 -0
  23. ciris_adapters/external_data_sql/manifest.json +195 -0
  24. ciris_adapters/external_data_sql/privacy_schema_loader.py +189 -0
  25. ciris_adapters/external_data_sql/protocol.py +101 -0
  26. ciris_adapters/external_data_sql/schemas.py +146 -0
  27. ciris_adapters/external_data_sql/service.py +1547 -0
  28. ciris_adapters/external_data_sql/service_old.py +492 -0
  29. ciris_adapters/home_assistant/__init__.py +63 -0
  30. ciris_adapters/home_assistant/adapter.py +201 -0
  31. ciris_adapters/home_assistant/communication_service.py +347 -0
  32. ciris_adapters/home_assistant/configurable.py +667 -0
  33. ciris_adapters/home_assistant/manifest.json +203 -0
  34. ciris_adapters/home_assistant/schemas.py +129 -0
  35. ciris_adapters/home_assistant/service.py +751 -0
  36. ciris_adapters/home_assistant/tool_service.py +441 -0
  37. ciris_adapters/mcp_client/__init__.py +82 -0
  38. ciris_adapters/mcp_client/adapter.py +847 -0
  39. ciris_adapters/mcp_client/config.py +280 -0
  40. ciris_adapters/mcp_client/configurable.py +422 -0
  41. ciris_adapters/mcp_client/manifest.json +185 -0
  42. ciris_adapters/mcp_client/mcp_communication_service.py +393 -0
  43. ciris_adapters/mcp_client/mcp_tool_service.py +463 -0
  44. ciris_adapters/mcp_client/mcp_wise_service.py +394 -0
  45. ciris_adapters/mcp_client/schemas.py +149 -0
  46. ciris_adapters/mcp_client/security.py +592 -0
  47. ciris_adapters/mcp_common/__init__.py +44 -0
  48. ciris_adapters/mcp_common/manifest.json +25 -0
  49. ciris_adapters/mcp_common/protocol.py +315 -0
  50. ciris_adapters/mcp_common/schemas.py +225 -0
  51. ciris_adapters/mcp_server/__init__.py +47 -0
  52. ciris_adapters/mcp_server/adapter.py +581 -0
  53. ciris_adapters/mcp_server/config.py +260 -0
  54. ciris_adapters/mcp_server/configurable.py +393 -0
  55. ciris_adapters/mcp_server/handlers.py +663 -0
  56. ciris_adapters/mcp_server/manifest.json +211 -0
  57. ciris_adapters/mcp_server/security.py +500 -0
  58. ciris_adapters/mock_llm/README.md +117 -0
  59. ciris_adapters/mock_llm/__init__.py +21 -0
  60. ciris_adapters/mock_llm/adapter.py +131 -0
  61. ciris_adapters/mock_llm/configurable.py +237 -0
  62. ciris_adapters/mock_llm/manifest.json +106 -0
  63. ciris_adapters/mock_llm/protocol.py +37 -0
  64. ciris_adapters/mock_llm/responses.py +520 -0
  65. ciris_adapters/mock_llm/responses_action_selection.py +1041 -0
  66. ciris_adapters/mock_llm/responses_epistemic.py +17 -0
  67. ciris_adapters/mock_llm/responses_feedback.py +27 -0
  68. ciris_adapters/mock_llm/schemas.py +35 -0
  69. ciris_adapters/mock_llm/service.py +294 -0
  70. ciris_adapters/navigation/__init__.py +21 -0
  71. ciris_adapters/navigation/adapter.py +129 -0
  72. ciris_adapters/navigation/configurable.py +239 -0
  73. ciris_adapters/navigation/manifest.json +104 -0
  74. ciris_adapters/navigation/service.py +487 -0
  75. ciris_adapters/reddit/README.md +132 -0
  76. ciris_adapters/reddit/REDDIT_ADAPTER_ANALYSIS.md +715 -0
  77. ciris_adapters/reddit/REDDIT_ADAPTER_SUMMARY.txt +278 -0
  78. ciris_adapters/reddit/REDDIT_ANALYSIS_INDEX.md +307 -0
  79. ciris_adapters/reddit/REDDIT_PRODUCTION_READINESS_PLAN.md +518 -0
  80. ciris_adapters/reddit/__init__.py +15 -0
  81. ciris_adapters/reddit/adapter.py +189 -0
  82. ciris_adapters/reddit/configurable.py +274 -0
  83. ciris_adapters/reddit/error_handler.py +307 -0
  84. ciris_adapters/reddit/manifest.json +218 -0
  85. ciris_adapters/reddit/observer.py +532 -0
  86. ciris_adapters/reddit/protocol.py +34 -0
  87. ciris_adapters/reddit/schemas.py +433 -0
  88. ciris_adapters/reddit/service.py +1471 -0
  89. ciris_adapters/sample_adapter/README.md +474 -0
  90. ciris_adapters/sample_adapter/__init__.py +45 -0
  91. ciris_adapters/sample_adapter/adapter.py +208 -0
  92. ciris_adapters/sample_adapter/configurable.py +469 -0
  93. ciris_adapters/sample_adapter/manifest.json +247 -0
  94. ciris_adapters/sample_adapter/services.py +486 -0
  95. ciris_adapters/weather/__init__.py +16 -0
  96. ciris_adapters/weather/adapter.py +130 -0
  97. ciris_adapters/weather/configurable.py +240 -0
  98. ciris_adapters/weather/manifest.json +156 -0
  99. ciris_adapters/weather/service.py +600 -0
  100. ciris_agent-1.7.7.dist-info/METADATA +284 -0
  101. ciris_agent-1.7.7.dist-info/RECORD +986 -0
  102. ciris_agent-1.7.7.dist-info/WHEEL +5 -0
  103. ciris_agent-1.7.7.dist-info/entry_points.txt +15 -0
  104. ciris_agent-1.7.7.dist-info/licenses/LICENSE +205 -0
  105. ciris_agent-1.7.7.dist-info/licenses/NOTICE +82 -0
  106. ciris_agent-1.7.7.dist-info/top_level.txt +4 -0
  107. ciris_engine/__init__.py +15 -0
  108. ciris_engine/ciris_templates/ally.yaml +632 -0
  109. ciris_engine/ciris_templates/default.yaml +411 -0
  110. ciris_engine/ciris_templates/echo-core.yaml +629 -0
  111. ciris_engine/ciris_templates/echo-speculative.yaml +764 -0
  112. ciris_engine/ciris_templates/echo.yaml +647 -0
  113. ciris_engine/ciris_templates/sage.yaml +332 -0
  114. ciris_engine/ciris_templates/scout.yaml +338 -0
  115. ciris_engine/ciris_templates/test.yaml +168 -0
  116. ciris_engine/cli.py +42 -0
  117. ciris_engine/config/CIRIS_SERVICES.json +19 -0
  118. ciris_engine/config/MODEL_CAPABILITIES.json +419 -0
  119. ciris_engine/config/PRICING_DATA.json +179 -0
  120. ciris_engine/config/__init__.py +50 -0
  121. ciris_engine/config/ciris_services.py +113 -0
  122. ciris_engine/config/model_capabilities.py +388 -0
  123. ciris_engine/config/pricing_models.py +276 -0
  124. ciris_engine/constants.py +35 -0
  125. ciris_engine/data/__init__.py +1 -0
  126. ciris_engine/data/covenant_1.0b.txt +978 -0
  127. ciris_engine/gui_static/11steps.svg +107 -0
  128. ciris_engine/gui_static/2x-schematics.png +0 -0
  129. ciris_engine/gui_static/404/index.html +1 -0
  130. ciris_engine/gui_static/404.html +1 -0
  131. ciris_engine/gui_static/_next/static/0edhkwDxd5UccTsCmtaBi/_buildManifest.js +1 -0
  132. ciris_engine/gui_static/_next/static/0edhkwDxd5UccTsCmtaBi/_ssgManifest.js +1 -0
  133. ciris_engine/gui_static/_next/static/U-3xTQao7hc2wnAi-Uekm/_buildManifest.js +1 -0
  134. ciris_engine/gui_static/_next/static/U-3xTQao7hc2wnAi-Uekm/_ssgManifest.js +1 -0
  135. ciris_engine/gui_static/_next/static/chunks/3297-60e86ba0f8a7b040.js +1 -0
  136. ciris_engine/gui_static/_next/static/chunks/3835-2aad4b7f5f8e4643.js +1 -0
  137. ciris_engine/gui_static/_next/static/chunks/4499-99a0bc47de0b8975.js +1 -0
  138. ciris_engine/gui_static/_next/static/chunks/4534-af88cd4ba6e99bff.js +1 -0
  139. ciris_engine/gui_static/_next/static/chunks/4541-84b455f9e0dc4cfe.js +1 -0
  140. ciris_engine/gui_static/_next/static/chunks/4789-61412711484754bb.js +1 -0
  141. ciris_engine/gui_static/_next/static/chunks/6539-c6398bc9d7018430.js +1 -0
  142. ciris_engine/gui_static/_next/static/chunks/704-8e827b26cc8c2d32.js +1 -0
  143. ciris_engine/gui_static/_next/static/chunks/704-fb45d630f3192c6f.js +1 -0
  144. ciris_engine/gui_static/_next/static/chunks/8072-de4952a2e6d2b33f.js +1 -0
  145. ciris_engine/gui_static/_next/static/chunks/8315-b91d03a3949db0af.js +1 -0
  146. ciris_engine/gui_static/_next/static/chunks/8386-f93a83ccbd789bd9.js +1 -0
  147. ciris_engine/gui_static/_next/static/chunks/87c73c54-781a7f35148d5433.js +1 -0
  148. ciris_engine/gui_static/_next/static/chunks/8903-fefea3339a02d41b.js +1 -0
  149. ciris_engine/gui_static/_next/static/chunks/9090-e66485adf8d9d990.js +1 -0
  150. ciris_engine/gui_static/_next/static/chunks/app/_not-found/page-a67d9808462c23b1.js +1 -0
  151. ciris_engine/gui_static/_next/static/chunks/app/account/api-keys/page-2d7ee1583bbbd02e.js +1 -0
  152. ciris_engine/gui_static/_next/static/chunks/app/account/api-keys/page-6a3c2bae6fe92b7b.js +1 -0
  153. ciris_engine/gui_static/_next/static/chunks/app/account/consent/page-2ed3a035136bc4e8.js +1 -0
  154. ciris_engine/gui_static/_next/static/chunks/app/account/consent/page-b2f5c91844a32422.js +1 -0
  155. ciris_engine/gui_static/_next/static/chunks/app/account/page-25b90f89af3ea58c.js +1 -0
  156. ciris_engine/gui_static/_next/static/chunks/app/account/page-b65d16c94ecaf69c.js +1 -0
  157. ciris_engine/gui_static/_next/static/chunks/app/account/privacy/page-675b6d05c8f9184f.js +1 -0
  158. ciris_engine/gui_static/_next/static/chunks/app/account/privacy/page-cbee2e1c8ab52145.js +1 -0
  159. ciris_engine/gui_static/_next/static/chunks/app/account/settings/page-0f44da06697cf9f0.js +1 -0
  160. ciris_engine/gui_static/_next/static/chunks/app/account/settings/page-563420253577edbf.js +1 -0
  161. ciris_engine/gui_static/_next/static/chunks/app/adapters/page-1854631018bc32be.js +1 -0
  162. ciris_engine/gui_static/_next/static/chunks/app/agents/page-8353752c176a7c70.js +1 -0
  163. ciris_engine/gui_static/_next/static/chunks/app/agents/page-f61a529f110a6040.js +1 -0
  164. ciris_engine/gui_static/_next/static/chunks/app/api-demo/page-7f19b9d20d39be28.js +1 -0
  165. ciris_engine/gui_static/_next/static/chunks/app/api-demo/page-d1063938f249b8bd.js +1 -0
  166. ciris_engine/gui_static/_next/static/chunks/app/audit/page-321b6728b8fff0bb.js +1 -0
  167. ciris_engine/gui_static/_next/static/chunks/app/audit/page-ebac35ca961a1277.js +1 -0
  168. ciris_engine/gui_static/_next/static/chunks/app/billing/page-6f3dc3bd02924f8e.js +1 -0
  169. ciris_engine/gui_static/_next/static/chunks/app/billing/page-fa4a469f814c821a.js +1 -0
  170. ciris_engine/gui_static/_next/static/chunks/app/comms/page-0d4f734269addd8f.js +1 -0
  171. ciris_engine/gui_static/_next/static/chunks/app/comms/page-79227d426050089c.js +1 -0
  172. ciris_engine/gui_static/_next/static/chunks/app/config/page-018d21d683b6e5bc.js +1 -0
  173. ciris_engine/gui_static/_next/static/chunks/app/config/page-2aa5a5363ca2a371.js +1 -0
  174. ciris_engine/gui_static/_next/static/chunks/app/consent/page-198373205fd316e2.js +1 -0
  175. ciris_engine/gui_static/_next/static/chunks/app/consent/page-f2ca39e7713b13f8.js +1 -0
  176. ciris_engine/gui_static/_next/static/chunks/app/dashboard/page-1dd5a196f643c60d.js +1 -0
  177. ciris_engine/gui_static/_next/static/chunks/app/dashboard/page-530a04d3abbb8cda.js +1 -0
  178. ciris_engine/gui_static/_next/static/chunks/app/docs/page-3193b06d094ab654.js +1 -0
  179. ciris_engine/gui_static/_next/static/chunks/app/docs/page-330e996dedb87aba.js +1 -0
  180. ciris_engine/gui_static/_next/static/chunks/app/layout-0a70f5fc460298b1.js +1 -0
  181. ciris_engine/gui_static/_next/static/chunks/app/layout-21f2f99dd5b336e9.js +1 -0
  182. ciris_engine/gui_static/_next/static/chunks/app/login/page-33240e6c6034a49d.js +1 -0
  183. ciris_engine/gui_static/_next/static/chunks/app/login/page-68ffab6d54a7fdcd.js +1 -0
  184. ciris_engine/gui_static/_next/static/chunks/app/logs/page-8a6167aecc4a475c.js +1 -0
  185. ciris_engine/gui_static/_next/static/chunks/app/memory/page-9ca8c5d0056de3ff.js +1 -0
  186. ciris_engine/gui_static/_next/static/chunks/app/memory/page-e961226941c18f81.js +1 -0
  187. ciris_engine/gui_static/_next/static/chunks/app/page-6fdb065a787a4974.js +1 -0
  188. ciris_engine/gui_static/_next/static/chunks/app/page-89f87d431be6064a.js +1 -0
  189. ciris_engine/gui_static/_next/static/chunks/app/runtime/page-2e728b9c43aa164d.js +1 -0
  190. ciris_engine/gui_static/_next/static/chunks/app/runtime/page-c7dd033dc40a72f0.js +1 -0
  191. ciris_engine/gui_static/_next/static/chunks/app/services/page-ae9f0bdf11d01a95.js +1 -0
  192. ciris_engine/gui_static/_next/static/chunks/app/services/page-b10feb79ca5d75e5.js +1 -0
  193. ciris_engine/gui_static/_next/static/chunks/app/sessions/page-13ebe7ef1c16ae11.js +1 -0
  194. ciris_engine/gui_static/_next/static/chunks/app/sessions/page-e6c82b16d617f785.js +1 -0
  195. ciris_engine/gui_static/_next/static/chunks/app/setup/page-0beb5f5b5a5c20fc.js +1 -0
  196. ciris_engine/gui_static/_next/static/chunks/app/setup/page-2595e729eae30c0e.js +1 -0
  197. ciris_engine/gui_static/_next/static/chunks/app/status-dashboard/page-1037c987aecc3653.js +1 -0
  198. ciris_engine/gui_static/_next/static/chunks/app/status-dashboard/page-2ffd147f6d3162ff.js +1 -0
  199. ciris_engine/gui_static/_next/static/chunks/app/system/page-2c5798d58cafcd91.js +1 -0
  200. ciris_engine/gui_static/_next/static/chunks/app/system/page-505b1ba4eceb01c3.js +1 -0
  201. ciris_engine/gui_static/_next/static/chunks/app/test-auth/page-b0cad31d5cb1b2fa.js +1 -0
  202. ciris_engine/gui_static/_next/static/chunks/app/test-auth/page-f3ecd7a8012df230.js +1 -0
  203. ciris_engine/gui_static/_next/static/chunks/app/test-login/page-f35117fdc4105801.js +1 -0
  204. ciris_engine/gui_static/_next/static/chunks/app/test-login/page-fb583a7924114906.js +1 -0
  205. ciris_engine/gui_static/_next/static/chunks/app/test-sdk/page-50f116fd76935563.js +1 -0
  206. ciris_engine/gui_static/_next/static/chunks/app/test-sdk/page-c37d8aa5ba623a44.js +1 -0
  207. ciris_engine/gui_static/_next/static/chunks/app/tools/page-429aec7a707777ef.js +1 -0
  208. ciris_engine/gui_static/_next/static/chunks/app/tools/page-5f705aad60e0c04e.js +1 -0
  209. ciris_engine/gui_static/_next/static/chunks/app/users/page-13476b8b0f3808cc.js +1 -0
  210. ciris_engine/gui_static/_next/static/chunks/app/users/page-7e500d154ed5bba4.js +1 -0
  211. ciris_engine/gui_static/_next/static/chunks/app/wa/page-cc4a9d8a5cb44d08.js +1 -0
  212. ciris_engine/gui_static/_next/static/chunks/app/wa/page-ec3e429efbc79230.js +1 -0
  213. ciris_engine/gui_static/_next/static/chunks/framework-9d29490f5ba089ba.js +1 -0
  214. ciris_engine/gui_static/_next/static/chunks/main-1f554952e47a82c4.js +1 -0
  215. ciris_engine/gui_static/_next/static/chunks/main-app-26fa8aed029082e5.js +1 -0
  216. ciris_engine/gui_static/_next/static/chunks/main-app-97b0486ef6bcef25.js +1 -0
  217. ciris_engine/gui_static/_next/static/chunks/pages/_app-6ce685456e616eb2.js +1 -0
  218. ciris_engine/gui_static/_next/static/chunks/pages/_error-d4bce98d93fe21e7.js +1 -0
  219. ciris_engine/gui_static/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  220. ciris_engine/gui_static/_next/static/chunks/webpack-fcebd240b7f8477d.js +1 -0
  221. ciris_engine/gui_static/_next/static/css/16b94b1fe0cc6e37.css +3 -0
  222. ciris_engine/gui_static/_next/static/css/77a24ceaae86deff.css +3 -0
  223. ciris_engine/gui_static/_next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  224. ciris_engine/gui_static/_next/static/media/747892c23ea88013-s.woff2 +0 -0
  225. ciris_engine/gui_static/_next/static/media/8d697b304b401681-s.woff2 +0 -0
  226. ciris_engine/gui_static/_next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  227. ciris_engine/gui_static/_next/static/media/9610d9e46709d722-s.woff2 +0 -0
  228. ciris_engine/gui_static/_next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  229. ciris_engine/gui_static/_next/static/media/d8298875641ec7d4-s.p.woff2 +0 -0
  230. ciris_engine/gui_static/account/api-keys/index.html +1 -0
  231. ciris_engine/gui_static/account/api-keys/index.txt +27 -0
  232. ciris_engine/gui_static/account/consent/index.html +1 -0
  233. ciris_engine/gui_static/account/consent/index.txt +27 -0
  234. ciris_engine/gui_static/account/index.html +1 -0
  235. ciris_engine/gui_static/account/index.txt +27 -0
  236. ciris_engine/gui_static/account/privacy/index.html +1 -0
  237. ciris_engine/gui_static/account/privacy/index.txt +27 -0
  238. ciris_engine/gui_static/account/settings/index.html +1 -0
  239. ciris_engine/gui_static/account/settings/index.txt +27 -0
  240. ciris_engine/gui_static/adapters/index.html +1 -0
  241. ciris_engine/gui_static/adapters/index.txt +27 -0
  242. ciris_engine/gui_static/agents/index.html +1 -0
  243. ciris_engine/gui_static/agents/index.txt +27 -0
  244. ciris_engine/gui_static/andrew-roberts-euBRXcx57T4-unsplash.jpg +0 -0
  245. ciris_engine/gui_static/api-demo/index.html +1 -0
  246. ciris_engine/gui_static/api-demo/index.txt +27 -0
  247. ciris_engine/gui_static/audit/index.html +1 -0
  248. ciris_engine/gui_static/audit/index.txt +27 -0
  249. ciris_engine/gui_static/billing/index.html +1 -0
  250. ciris_engine/gui_static/billing/index.txt +27 -0
  251. ciris_engine/gui_static/blurryinfo.png +0 -0
  252. ciris_engine/gui_static/chip-vincent-PkQDwfl9Flc-unsplash.jpg +0 -0
  253. ciris_engine/gui_static/ciris-architecture.svg +338 -0
  254. ciris_engine/gui_static/comms/index.html +1 -0
  255. ciris_engine/gui_static/comms/index.txt +27 -0
  256. ciris_engine/gui_static/config/index.html +1 -0
  257. ciris_engine/gui_static/config/index.txt +27 -0
  258. ciris_engine/gui_static/consent/index.html +1 -0
  259. ciris_engine/gui_static/consent/index.txt +27 -0
  260. ciris_engine/gui_static/dashboard/index.html +1 -0
  261. ciris_engine/gui_static/dashboard/index.txt +27 -0
  262. ciris_engine/gui_static/docs/index.html +1 -0
  263. ciris_engine/gui_static/docs/index.txt +27 -0
  264. ciris_engine/gui_static/eric.png +0 -0
  265. ciris_engine/gui_static/file.svg +1 -0
  266. ciris_engine/gui_static/globe.svg +1 -0
  267. ciris_engine/gui_static/index.html +1 -0
  268. ciris_engine/gui_static/index.txt +27 -0
  269. ciris_engine/gui_static/infogfx-1@2x.png +0 -0
  270. ciris_engine/gui_static/infogfx-2.png +0 -0
  271. ciris_engine/gui_static/infogfx-dark-1.png +0 -0
  272. ciris_engine/gui_static/kelly-vohs-soSTXmIxTDU-unsplash.jpg +0 -0
  273. ciris_engine/gui_static/login/index.html +1 -0
  274. ciris_engine/gui_static/login/index.txt +27 -0
  275. ciris_engine/gui_static/logs/index.html +1 -0
  276. ciris_engine/gui_static/logs/index.txt +27 -0
  277. ciris_engine/gui_static/memory/index.html +1 -0
  278. ciris_engine/gui_static/memory/index.txt +27 -0
  279. ciris_engine/gui_static/nathan-farrish-ArcTfEoBgzs-unsplash.jpg +0 -0
  280. ciris_engine/gui_static/next.svg +1 -0
  281. ciris_engine/gui_static/overview.svg +512 -0
  282. ciris_engine/gui_static/overview1.svg +407 -0
  283. ciris_engine/gui_static/overview2.svg +370 -0
  284. ciris_engine/gui_static/pipeline-visualization.svg +278 -0
  285. ciris_engine/gui_static/privacy-policy.html +160 -0
  286. ciris_engine/gui_static/runtime/index.html +8 -0
  287. ciris_engine/gui_static/runtime/index.txt +27 -0
  288. ciris_engine/gui_static/services/index.html +1 -0
  289. ciris_engine/gui_static/services/index.txt +27 -0
  290. ciris_engine/gui_static/sessions/index.html +1 -0
  291. ciris_engine/gui_static/sessions/index.txt +27 -0
  292. ciris_engine/gui_static/setup/index.html +1 -0
  293. ciris_engine/gui_static/setup/index.txt +27 -0
  294. ciris_engine/gui_static/status-dashboard/index.html +1 -0
  295. ciris_engine/gui_static/status-dashboard/index.txt +27 -0
  296. ciris_engine/gui_static/system/index.html +1 -0
  297. ciris_engine/gui_static/system/index.txt +27 -0
  298. ciris_engine/gui_static/terms-of-service.html +174 -0
  299. ciris_engine/gui_static/test-auth/index.html +1 -0
  300. ciris_engine/gui_static/test-auth/index.txt +27 -0
  301. ciris_engine/gui_static/test-login/index.html +1 -0
  302. ciris_engine/gui_static/test-login/index.txt +27 -0
  303. ciris_engine/gui_static/test-sdk/index.html +1 -0
  304. ciris_engine/gui_static/test-sdk/index.txt +27 -0
  305. ciris_engine/gui_static/tools/index.html +1 -0
  306. ciris_engine/gui_static/tools/index.txt +27 -0
  307. ciris_engine/gui_static/users/index.html +1 -0
  308. ciris_engine/gui_static/users/index.txt +27 -0
  309. ciris_engine/gui_static/vercel.svg +1 -0
  310. ciris_engine/gui_static/videos/video1.mp4 +0 -0
  311. ciris_engine/gui_static/videos/video3.mp4 +0 -0
  312. ciris_engine/gui_static/wa/index.html +1 -0
  313. ciris_engine/gui_static/wa/index.txt +27 -0
  314. ciris_engine/gui_static/window.svg +1 -0
  315. ciris_engine/logic/__init__.py +8 -0
  316. ciris_engine/logic/adapters/__init__.py +74 -0
  317. ciris_engine/logic/adapters/api/__init__.py +5 -0
  318. ciris_engine/logic/adapters/api/adapter.py +1037 -0
  319. ciris_engine/logic/adapters/api/api_communication.py +370 -0
  320. ciris_engine/logic/adapters/api/api_document.py +330 -0
  321. ciris_engine/logic/adapters/api/api_observer.py +24 -0
  322. ciris_engine/logic/adapters/api/api_runtime_control.py +388 -0
  323. ciris_engine/logic/adapters/api/api_tools.py +299 -0
  324. ciris_engine/logic/adapters/api/api_vision.py +215 -0
  325. ciris_engine/logic/adapters/api/app.py +272 -0
  326. ciris_engine/logic/adapters/api/auth.py +159 -0
  327. ciris_engine/logic/adapters/api/config.py +101 -0
  328. ciris_engine/logic/adapters/api/constants.py +55 -0
  329. ciris_engine/logic/adapters/api/dependencies/__init__.py +1 -0
  330. ciris_engine/logic/adapters/api/dependencies/auth.py +260 -0
  331. ciris_engine/logic/adapters/api/endpoints/__init__.py +1 -0
  332. ciris_engine/logic/adapters/api/endpoints/emergency.py +86 -0
  333. ciris_engine/logic/adapters/api/middleware/__init__.py +1 -0
  334. ciris_engine/logic/adapters/api/middleware/rate_limiter.py +302 -0
  335. ciris_engine/logic/adapters/api/models.py +29 -0
  336. ciris_engine/logic/adapters/api/routes/__init__.py +52 -0
  337. ciris_engine/logic/adapters/api/routes/agent.py +1762 -0
  338. ciris_engine/logic/adapters/api/routes/audit.py +707 -0
  339. ciris_engine/logic/adapters/api/routes/auth.py +1745 -0
  340. ciris_engine/logic/adapters/api/routes/billing.py +895 -0
  341. ciris_engine/logic/adapters/api/routes/config.py +329 -0
  342. ciris_engine/logic/adapters/api/routes/connectors.py +534 -0
  343. ciris_engine/logic/adapters/api/routes/consent.py +637 -0
  344. ciris_engine/logic/adapters/api/routes/dsar.py +637 -0
  345. ciris_engine/logic/adapters/api/routes/dsar_multi_source.py +484 -0
  346. ciris_engine/logic/adapters/api/routes/emergency.py +302 -0
  347. ciris_engine/logic/adapters/api/routes/memory.py +733 -0
  348. ciris_engine/logic/adapters/api/routes/memory_filters.py +230 -0
  349. ciris_engine/logic/adapters/api/routes/memory_models.py +112 -0
  350. ciris_engine/logic/adapters/api/routes/memory_queries.py +236 -0
  351. ciris_engine/logic/adapters/api/routes/memory_query_helpers.py +394 -0
  352. ciris_engine/logic/adapters/api/routes/memory_visualization.py +359 -0
  353. ciris_engine/logic/adapters/api/routes/memory_visualization_helpers.py +110 -0
  354. ciris_engine/logic/adapters/api/routes/partnership.py +541 -0
  355. ciris_engine/logic/adapters/api/routes/setup.py +1374 -0
  356. ciris_engine/logic/adapters/api/routes/system.py +3049 -0
  357. ciris_engine/logic/adapters/api/routes/system_extensions.py +952 -0
  358. ciris_engine/logic/adapters/api/routes/telemetry.py +1987 -0
  359. ciris_engine/logic/adapters/api/routes/telemetry_converters.py +141 -0
  360. ciris_engine/logic/adapters/api/routes/telemetry_helpers.py +111 -0
  361. ciris_engine/logic/adapters/api/routes/telemetry_logs_reader.py +280 -0
  362. ciris_engine/logic/adapters/api/routes/telemetry_metrics.py +131 -0
  363. ciris_engine/logic/adapters/api/routes/telemetry_models.py +190 -0
  364. ciris_engine/logic/adapters/api/routes/telemetry_otlp.py +878 -0
  365. ciris_engine/logic/adapters/api/routes/telemetry_resource_helpers.py +191 -0
  366. ciris_engine/logic/adapters/api/routes/tickets.py +541 -0
  367. ciris_engine/logic/adapters/api/routes/tools.py +556 -0
  368. ciris_engine/logic/adapters/api/routes/transparency.py +281 -0
  369. ciris_engine/logic/adapters/api/routes/users.py +981 -0
  370. ciris_engine/logic/adapters/api/routes/verification.py +373 -0
  371. ciris_engine/logic/adapters/api/routes/wa.py +369 -0
  372. ciris_engine/logic/adapters/api/service_configuration.py +177 -0
  373. ciris_engine/logic/adapters/api/services/__init__.py +1 -0
  374. ciris_engine/logic/adapters/api/services/auth_service.py +1417 -0
  375. ciris_engine/logic/adapters/api/services/oauth_security.py +68 -0
  376. ciris_engine/logic/adapters/base.py +141 -0
  377. ciris_engine/logic/adapters/base_adapter.py +73 -0
  378. ciris_engine/logic/adapters/base_observer.py +1141 -0
  379. ciris_engine/logic/adapters/base_vision.py +312 -0
  380. ciris_engine/logic/adapters/cirisnode_client.py +307 -0
  381. ciris_engine/logic/adapters/cli/__init__.py +3 -0
  382. ciris_engine/logic/adapters/cli/adapter.py +207 -0
  383. ciris_engine/logic/adapters/cli/cli_adapter.py +902 -0
  384. ciris_engine/logic/adapters/cli/cli_observer.py +268 -0
  385. ciris_engine/logic/adapters/cli/cli_tools.py +427 -0
  386. ciris_engine/logic/adapters/cli/cli_wa_service.py +134 -0
  387. ciris_engine/logic/adapters/cli/config.py +73 -0
  388. ciris_engine/logic/adapters/discord/__init__.py +3 -0
  389. ciris_engine/logic/adapters/discord/adapter.py +783 -0
  390. ciris_engine/logic/adapters/discord/ciris_discord_client.py +159 -0
  391. ciris_engine/logic/adapters/discord/config.py +177 -0
  392. ciris_engine/logic/adapters/discord/constants.py +185 -0
  393. ciris_engine/logic/adapters/discord/discord-stubs.pyi +50 -0
  394. ciris_engine/logic/adapters/discord/discord_adapter.py +1584 -0
  395. ciris_engine/logic/adapters/discord/discord_audit.py +150 -0
  396. ciris_engine/logic/adapters/discord/discord_channel_manager.py +351 -0
  397. ciris_engine/logic/adapters/discord/discord_connection_manager.py +313 -0
  398. ciris_engine/logic/adapters/discord/discord_embed_formatter.py +369 -0
  399. ciris_engine/logic/adapters/discord/discord_error_classifier.py +302 -0
  400. ciris_engine/logic/adapters/discord/discord_error_handler.py +316 -0
  401. ciris_engine/logic/adapters/discord/discord_guidance_handler.py +460 -0
  402. ciris_engine/logic/adapters/discord/discord_message_handler.py +207 -0
  403. ciris_engine/logic/adapters/discord/discord_observer.py +670 -0
  404. ciris_engine/logic/adapters/discord/discord_rate_limiter.py +249 -0
  405. ciris_engine/logic/adapters/discord/discord_reaction_handler.py +278 -0
  406. ciris_engine/logic/adapters/discord/discord_tool_handler.py +465 -0
  407. ciris_engine/logic/adapters/discord/discord_tool_service.py +790 -0
  408. ciris_engine/logic/adapters/discord/discord_tools.py +90 -0
  409. ciris_engine/logic/adapters/discord/discord_vision_helper.py +148 -0
  410. ciris_engine/logic/adapters/discord/py.typed +0 -0
  411. ciris_engine/logic/adapters/document_parser.py +320 -0
  412. ciris_engine/logic/audit/__init__.py +10 -0
  413. ciris_engine/logic/audit/hash_chain.py +313 -0
  414. ciris_engine/logic/audit/signature_manager.py +352 -0
  415. ciris_engine/logic/audit/verifier.py +408 -0
  416. ciris_engine/logic/buses/__init__.py +21 -0
  417. ciris_engine/logic/buses/base_bus.py +178 -0
  418. ciris_engine/logic/buses/bus_manager.py +121 -0
  419. ciris_engine/logic/buses/communication_bus.py +387 -0
  420. ciris_engine/logic/buses/llm_bus.py +722 -0
  421. ciris_engine/logic/buses/memory_bus.py +577 -0
  422. ciris_engine/logic/buses/prohibitions.py +502 -0
  423. ciris_engine/logic/buses/runtime_control_bus.py +539 -0
  424. ciris_engine/logic/buses/tool_bus.py +482 -0
  425. ciris_engine/logic/buses/wise_bus.py +684 -0
  426. ciris_engine/logic/config/__init__.py +25 -0
  427. ciris_engine/logic/config/bootstrap.py +255 -0
  428. ciris_engine/logic/config/config_accessor.py +202 -0
  429. ciris_engine/logic/config/db_paths.py +194 -0
  430. ciris_engine/logic/config/env_utils.py +39 -0
  431. ciris_engine/logic/conscience/__init__.py +16 -0
  432. ciris_engine/logic/conscience/build_deferral_package.py +0 -0
  433. ciris_engine/logic/conscience/core.py +688 -0
  434. ciris_engine/logic/conscience/interface.py +33 -0
  435. ciris_engine/logic/conscience/registry.py +76 -0
  436. ciris_engine/logic/conscience/thought_depth_guardrail.py +231 -0
  437. ciris_engine/logic/conscience/updated_status_conscience.py +156 -0
  438. ciris_engine/logic/context/__init__.py +10 -0
  439. ciris_engine/logic/context/batch_context.py +550 -0
  440. ciris_engine/logic/context/builder.py +149 -0
  441. ciris_engine/logic/context/channel_resolution.py +136 -0
  442. ciris_engine/logic/context/secrets_snapshot.py +52 -0
  443. ciris_engine/logic/context/system_snapshot.py +116 -0
  444. ciris_engine/logic/context/system_snapshot_helpers.py +1651 -0
  445. ciris_engine/logic/covenant/__init__.py +33 -0
  446. ciris_engine/logic/covenant/executor.py +303 -0
  447. ciris_engine/logic/covenant/extractor.py +382 -0
  448. ciris_engine/logic/covenant/handler.py +241 -0
  449. ciris_engine/logic/covenant/verifier.py +383 -0
  450. ciris_engine/logic/dma/__init__.py +15 -0
  451. ciris_engine/logic/dma/action_selection/__init__.py +11 -0
  452. ciris_engine/logic/dma/action_selection/action_instruction_generator.py +444 -0
  453. ciris_engine/logic/dma/action_selection/context_builder.py +508 -0
  454. ciris_engine/logic/dma/action_selection/faculty_integration.py +193 -0
  455. ciris_engine/logic/dma/action_selection/special_cases.py +132 -0
  456. ciris_engine/logic/dma/action_selection_pdma.py +365 -0
  457. ciris_engine/logic/dma/base_dma.py +335 -0
  458. ciris_engine/logic/dma/csdma.py +239 -0
  459. ciris_engine/logic/dma/dma_executor.py +575 -0
  460. ciris_engine/logic/dma/dsdma_base.py +410 -0
  461. ciris_engine/logic/dma/exceptions.py +4 -0
  462. ciris_engine/logic/dma/factory.py +150 -0
  463. ciris_engine/logic/dma/pdma.py +120 -0
  464. ciris_engine/logic/dma/prompt_loader.py +189 -0
  465. ciris_engine/logic/dma/prompts/action_selection_pdma.yml +58 -0
  466. ciris_engine/logic/dma/prompts/csdma_common_sense.yml +28 -0
  467. ciris_engine/logic/dma/prompts/dsdma_base.yml +17 -0
  468. ciris_engine/logic/dma/prompts/pdma_ethical.yml +42 -0
  469. ciris_engine/logic/formatters/__init__.py +26 -0
  470. ciris_engine/logic/formatters/crisis_resources.py +80 -0
  471. ciris_engine/logic/formatters/escalation.py +21 -0
  472. ciris_engine/logic/formatters/identity.py +224 -0
  473. ciris_engine/logic/formatters/prompt_blocks.py +64 -0
  474. ciris_engine/logic/formatters/system_snapshot.py +193 -0
  475. ciris_engine/logic/formatters/user_profiles.py +108 -0
  476. ciris_engine/logic/handlers/__init__.py +1 -0
  477. ciris_engine/logic/handlers/control/__init__.py +1 -0
  478. ciris_engine/logic/handlers/control/defer_handler.py +195 -0
  479. ciris_engine/logic/handlers/control/ponder_handler.py +154 -0
  480. ciris_engine/logic/handlers/control/reject_handler.py +81 -0
  481. ciris_engine/logic/handlers/external/__init__.py +1 -0
  482. ciris_engine/logic/handlers/external/observe_handler.py +154 -0
  483. ciris_engine/logic/handlers/external/speak_handler.py +250 -0
  484. ciris_engine/logic/handlers/external/tool_handler.py +148 -0
  485. ciris_engine/logic/handlers/memory/__init__.py +1 -0
  486. ciris_engine/logic/handlers/memory/forget_handler.py +107 -0
  487. ciris_engine/logic/handlers/memory/memorize_handler.py +391 -0
  488. ciris_engine/logic/handlers/memory/recall_handler.py +213 -0
  489. ciris_engine/logic/handlers/terminal/__init__.py +1 -0
  490. ciris_engine/logic/handlers/terminal/task_complete_handler.py +299 -0
  491. ciris_engine/logic/infrastructure/__init__.py +1 -0
  492. ciris_engine/logic/infrastructure/handlers/__init__.py +8 -0
  493. ciris_engine/logic/infrastructure/handlers/action_dispatcher.py +382 -0
  494. ciris_engine/logic/infrastructure/handlers/base_handler.py +450 -0
  495. ciris_engine/logic/infrastructure/handlers/exceptions.py +2 -0
  496. ciris_engine/logic/infrastructure/handlers/handler_registry.py +59 -0
  497. ciris_engine/logic/infrastructure/handlers/helpers.py +55 -0
  498. ciris_engine/logic/infrastructure/step_streaming.py +149 -0
  499. ciris_engine/logic/infrastructure/sub_services/__init__.py +1 -0
  500. ciris_engine/logic/infrastructure/sub_services/identity_variance_monitor.py +1035 -0
  501. ciris_engine/logic/infrastructure/sub_services/pattern_analysis_loop.py +758 -0
  502. ciris_engine/logic/infrastructure/sub_services/wa_cli_bootstrap.py +229 -0
  503. ciris_engine/logic/infrastructure/sub_services/wa_cli_display.py +176 -0
  504. ciris_engine/logic/infrastructure/sub_services/wa_cli_oauth.py +404 -0
  505. ciris_engine/logic/infrastructure/sub_services/wa_cli_wizard.py +181 -0
  506. ciris_engine/logic/persistence/__init__.py +130 -0
  507. ciris_engine/logic/persistence/analytics.py +97 -0
  508. ciris_engine/logic/persistence/db/__init__.py +28 -0
  509. ciris_engine/logic/persistence/db/core.py +520 -0
  510. ciris_engine/logic/persistence/db/dialect.py +380 -0
  511. ciris_engine/logic/persistence/db/execution_helpers.py +216 -0
  512. ciris_engine/logic/persistence/db/migration_runner.py +191 -0
  513. ciris_engine/logic/persistence/db/operations.py +313 -0
  514. ciris_engine/logic/persistence/db/query_builder.py +232 -0
  515. ciris_engine/logic/persistence/db/retry.py +154 -0
  516. ciris_engine/logic/persistence/db/setup.py +18 -0
  517. ciris_engine/logic/persistence/migrations/postgres/001_initial_schema.sql +4 -0
  518. ciris_engine/logic/persistence/migrations/postgres/002_add_retry_status.sql +3 -0
  519. ciris_engine/logic/persistence/migrations/postgres/003_add_task_update_tracking.sql +8 -0
  520. ciris_engine/logic/persistence/migrations/postgres/004_add_occurrence_id.sql +54 -0
  521. ciris_engine/logic/persistence/migrations/postgres/005_add_consolidation_locks.sql +22 -0
  522. ciris_engine/logic/persistence/migrations/postgres/006_add_correlation_id_unique_index.sql +16 -0
  523. ciris_engine/logic/persistence/migrations/postgres/007_add_dsar_tickets.sql +39 -0
  524. ciris_engine/logic/persistence/migrations/postgres/008_rename_to_tickets_add_sop.sql +123 -0
  525. ciris_engine/logic/persistence/migrations/postgres/009_add_ticket_status_columns.sql +39 -0
  526. ciris_engine/logic/persistence/migrations/postgres/010_add_images_to_tasks.sql +5 -0
  527. ciris_engine/logic/persistence/migrations/sqlite/001_initial_schema.sql +357 -0
  528. ciris_engine/logic/persistence/migrations/sqlite/002_add_retry_status.sql +3 -0
  529. ciris_engine/logic/persistence/migrations/sqlite/003_add_task_update_tracking.sql +8 -0
  530. ciris_engine/logic/persistence/migrations/sqlite/004_add_occurrence_id.sql +45 -0
  531. ciris_engine/logic/persistence/migrations/sqlite/005_add_consolidation_locks.sql +22 -0
  532. ciris_engine/logic/persistence/migrations/sqlite/006_add_correlation_id_unique_index.sql +16 -0
  533. ciris_engine/logic/persistence/migrations/sqlite/007_add_dsar_tickets.sql +39 -0
  534. ciris_engine/logic/persistence/migrations/sqlite/008_rename_to_tickets_add_sop.sql +120 -0
  535. ciris_engine/logic/persistence/migrations/sqlite/009_add_ticket_status_columns.sql +129 -0
  536. ciris_engine/logic/persistence/migrations/sqlite/010_add_images_to_tasks.sql +17 -0
  537. ciris_engine/logic/persistence/models/__init__.py +141 -0
  538. ciris_engine/logic/persistence/models/correlations.py +881 -0
  539. ciris_engine/logic/persistence/models/deferral.py +68 -0
  540. ciris_engine/logic/persistence/models/dsar.py +286 -0
  541. ciris_engine/logic/persistence/models/graph.py +362 -0
  542. ciris_engine/logic/persistence/models/identity.py +264 -0
  543. ciris_engine/logic/persistence/models/queue_status.py +139 -0
  544. ciris_engine/logic/persistence/models/tasks.py +1043 -0
  545. ciris_engine/logic/persistence/models/thoughts.py +400 -0
  546. ciris_engine/logic/persistence/models/tickets.py +518 -0
  547. ciris_engine/logic/persistence/stores/__init__.py +13 -0
  548. ciris_engine/logic/persistence/stores/auth_helpers.py +117 -0
  549. ciris_engine/logic/persistence/stores/authentication_store.py +414 -0
  550. ciris_engine/logic/persistence/utils.py +212 -0
  551. ciris_engine/logic/processors/__init__.py +30 -0
  552. ciris_engine/logic/processors/core/__init__.py +1 -0
  553. ciris_engine/logic/processors/core/base_processor.py +280 -0
  554. ciris_engine/logic/processors/core/main_processor.py +1777 -0
  555. ciris_engine/logic/processors/core/step_decorators.py +1583 -0
  556. ciris_engine/logic/processors/core/thought_processor/__init__.py +20 -0
  557. ciris_engine/logic/processors/core/thought_processor/action_execution.py +49 -0
  558. ciris_engine/logic/processors/core/thought_processor/conscience_execution.py +382 -0
  559. ciris_engine/logic/processors/core/thought_processor/finalize_action.py +66 -0
  560. ciris_engine/logic/processors/core/thought_processor/gather_context.py +120 -0
  561. ciris_engine/logic/processors/core/thought_processor/main.py +920 -0
  562. ciris_engine/logic/processors/core/thought_processor/perform_aspdma.py +86 -0
  563. ciris_engine/logic/processors/core/thought_processor/perform_dmas.py +106 -0
  564. ciris_engine/logic/processors/core/thought_processor/recursive_processing.py +237 -0
  565. ciris_engine/logic/processors/core/thought_processor/round_complete.py +52 -0
  566. ciris_engine/logic/processors/core/thought_processor/start_round.py +64 -0
  567. ciris_engine/logic/processors/exceptions.py +59 -0
  568. ciris_engine/logic/processors/states/__init__.py +1 -0
  569. ciris_engine/logic/processors/states/dream_processor.py +1381 -0
  570. ciris_engine/logic/processors/states/play_processor.py +141 -0
  571. ciris_engine/logic/processors/states/shutdown_processor.py +623 -0
  572. ciris_engine/logic/processors/states/solitude_processor.py +305 -0
  573. ciris_engine/logic/processors/states/wakeup_processor.py +802 -0
  574. ciris_engine/logic/processors/states/work_processor.py +742 -0
  575. ciris_engine/logic/processors/support/__init__.py +1 -0
  576. ciris_engine/logic/processors/support/dma_orchestrator.py +336 -0
  577. ciris_engine/logic/processors/support/processing_queue.py +133 -0
  578. ciris_engine/logic/processors/support/shutdown_condition_evaluator.py +294 -0
  579. ciris_engine/logic/processors/support/state_manager.py +358 -0
  580. ciris_engine/logic/processors/support/task_manager.py +303 -0
  581. ciris_engine/logic/processors/support/thought_escalation.py +116 -0
  582. ciris_engine/logic/processors/support/thought_manager.py +328 -0
  583. ciris_engine/logic/processors/support/thought_manager_enhanced.py +105 -0
  584. ciris_engine/logic/registries/__init__.py +34 -0
  585. ciris_engine/logic/registries/base.py +653 -0
  586. ciris_engine/logic/registries/circuit_breaker.py +275 -0
  587. ciris_engine/logic/registries/typed_registries.py +184 -0
  588. ciris_engine/logic/runtime/__init__.py +7 -0
  589. ciris_engine/logic/runtime/adapter_loader.py +261 -0
  590. ciris_engine/logic/runtime/adapter_manager.py +1053 -0
  591. ciris_engine/logic/runtime/ciris_runtime.py +2342 -0
  592. ciris_engine/logic/runtime/ciris_runtime_helpers.py +923 -0
  593. ciris_engine/logic/runtime/component_builder.py +361 -0
  594. ciris_engine/logic/runtime/identity_manager.py +219 -0
  595. ciris_engine/logic/runtime/module_loader.py +207 -0
  596. ciris_engine/logic/runtime/prevent_sideeffects.py +30 -0
  597. ciris_engine/logic/runtime/runtime_interface.py +23 -0
  598. ciris_engine/logic/runtime/service_initializer.py +1623 -0
  599. ciris_engine/logic/secrets/__init__.py +30 -0
  600. ciris_engine/logic/secrets/encryption.py +175 -0
  601. ciris_engine/logic/secrets/filter.py +295 -0
  602. ciris_engine/logic/secrets/service.py +652 -0
  603. ciris_engine/logic/secrets/store.py +669 -0
  604. ciris_engine/logic/services/__init__.py +1 -0
  605. ciris_engine/logic/services/adaptation/__init__.py +3 -0
  606. ciris_engine/logic/services/base_graph_service.py +142 -0
  607. ciris_engine/logic/services/base_infrastructure_service.py +69 -0
  608. ciris_engine/logic/services/base_scheduled_service.py +136 -0
  609. ciris_engine/logic/services/base_service.py +247 -0
  610. ciris_engine/logic/services/governance/__init__.py +3 -0
  611. ciris_engine/logic/services/governance/adaptive_filter/__init__.py +14 -0
  612. ciris_engine/logic/services/governance/adaptive_filter/service.py +818 -0
  613. ciris_engine/logic/services/governance/consent/__init__.py +53 -0
  614. ciris_engine/logic/services/governance/consent/air.py +403 -0
  615. ciris_engine/logic/services/governance/consent/decay.py +324 -0
  616. ciris_engine/logic/services/governance/consent/dsar_automation.py +589 -0
  617. ciris_engine/logic/services/governance/consent/exceptions.py +106 -0
  618. ciris_engine/logic/services/governance/consent/metrics.py +270 -0
  619. ciris_engine/logic/services/governance/consent/partnership.py +533 -0
  620. ciris_engine/logic/services/governance/consent/service.py +1256 -0
  621. ciris_engine/logic/services/governance/dsar/__init__.py +29 -0
  622. ciris_engine/logic/services/governance/dsar/orchestrator.py +977 -0
  623. ciris_engine/logic/services/governance/dsar/schemas.py +141 -0
  624. ciris_engine/logic/services/governance/dsar/signature_service.py +283 -0
  625. ciris_engine/logic/services/governance/self_observation/__init__.py +20 -0
  626. ciris_engine/logic/services/governance/self_observation/service.py +1153 -0
  627. ciris_engine/logic/services/governance/visibility/__init__.py +17 -0
  628. ciris_engine/logic/services/governance/visibility/service.py +512 -0
  629. ciris_engine/logic/services/governance/wise_authority/__init__.py +15 -0
  630. ciris_engine/logic/services/governance/wise_authority/service.py +827 -0
  631. ciris_engine/logic/services/graph/__init__.py +5 -0
  632. ciris_engine/logic/services/graph/audit_service/__init__.py +5 -0
  633. ciris_engine/logic/services/graph/audit_service/service.py +1675 -0
  634. ciris_engine/logic/services/graph/base.py +208 -0
  635. ciris_engine/logic/services/graph/config_service/__init__.py +5 -0
  636. ciris_engine/logic/services/graph/config_service/service.py +372 -0
  637. ciris_engine/logic/services/graph/incident_service/__init__.py +5 -0
  638. ciris_engine/logic/services/graph/incident_service/service.py +803 -0
  639. ciris_engine/logic/services/graph/memory_service.py +1120 -0
  640. ciris_engine/logic/services/graph/telemetry_service/__init__.py +5 -0
  641. ciris_engine/logic/services/graph/telemetry_service/exceptions.py +104 -0
  642. ciris_engine/logic/services/graph/telemetry_service/helpers.py +1337 -0
  643. ciris_engine/logic/services/graph/telemetry_service/service.py +2429 -0
  644. ciris_engine/logic/services/graph/tsdb_consolidation/__init__.py +17 -0
  645. ciris_engine/logic/services/graph/tsdb_consolidation/aggregation_helpers.py +355 -0
  646. ciris_engine/logic/services/graph/tsdb_consolidation/cleanup_helpers.py +438 -0
  647. ciris_engine/logic/services/graph/tsdb_consolidation/compressor.py +260 -0
  648. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/__init__.py +27 -0
  649. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/audit.py +326 -0
  650. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/conversation.py +291 -0
  651. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/memory.py +197 -0
  652. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/metrics.py +251 -0
  653. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/task.py +257 -0
  654. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/trace.py +363 -0
  655. ciris_engine/logic/services/graph/tsdb_consolidation/data_converter.py +545 -0
  656. ciris_engine/logic/services/graph/tsdb_consolidation/date_calculation_helpers.py +193 -0
  657. ciris_engine/logic/services/graph/tsdb_consolidation/db_query_helpers.py +296 -0
  658. ciris_engine/logic/services/graph/tsdb_consolidation/edge_helpers.py +92 -0
  659. ciris_engine/logic/services/graph/tsdb_consolidation/edge_manager.py +896 -0
  660. ciris_engine/logic/services/graph/tsdb_consolidation/extensive_helpers.py +322 -0
  661. ciris_engine/logic/services/graph/tsdb_consolidation/period_manager.py +152 -0
  662. ciris_engine/logic/services/graph/tsdb_consolidation/profound_helpers.py +277 -0
  663. ciris_engine/logic/services/graph/tsdb_consolidation/query_manager.py +812 -0
  664. ciris_engine/logic/services/graph/tsdb_consolidation/service.py +1692 -0
  665. ciris_engine/logic/services/graph/tsdb_consolidation/sql_builders.py +363 -0
  666. ciris_engine/logic/services/infrastructure/__init__.py +1 -0
  667. ciris_engine/logic/services/infrastructure/authentication/__init__.py +5 -0
  668. ciris_engine/logic/services/infrastructure/authentication/service.py +1634 -0
  669. ciris_engine/logic/services/infrastructure/database_maintenance/__init__.py +15 -0
  670. ciris_engine/logic/services/infrastructure/database_maintenance/service.py +764 -0
  671. ciris_engine/logic/services/infrastructure/resource_monitor/__init__.py +7 -0
  672. ciris_engine/logic/services/infrastructure/resource_monitor/ciris_billing_provider.py +755 -0
  673. ciris_engine/logic/services/infrastructure/resource_monitor/service.py +409 -0
  674. ciris_engine/logic/services/infrastructure/resource_monitor/simple_credit_provider.py +129 -0
  675. ciris_engine/logic/services/lifecycle/__init__.py +3 -0
  676. ciris_engine/logic/services/lifecycle/initialization/__init__.py +10 -0
  677. ciris_engine/logic/services/lifecycle/initialization/service.py +312 -0
  678. ciris_engine/logic/services/lifecycle/scheduler/__init__.py +5 -0
  679. ciris_engine/logic/services/lifecycle/scheduler/service.py +607 -0
  680. ciris_engine/logic/services/lifecycle/shutdown/__init__.py +9 -0
  681. ciris_engine/logic/services/lifecycle/shutdown/service.py +378 -0
  682. ciris_engine/logic/services/lifecycle/time/__init__.py +15 -0
  683. ciris_engine/logic/services/lifecycle/time/service.py +259 -0
  684. ciris_engine/logic/services/memory_service/__init__.py +8 -0
  685. ciris_engine/logic/services/mixins/__init__.py +13 -0
  686. ciris_engine/logic/services/mixins/example_usage.py +200 -0
  687. ciris_engine/logic/services/mixins/request_metrics.py +179 -0
  688. ciris_engine/logic/services/runtime/__init__.py +3 -0
  689. ciris_engine/logic/services/runtime/adapter_configuration/__init__.py +16 -0
  690. ciris_engine/logic/services/runtime/adapter_configuration/service.py +674 -0
  691. ciris_engine/logic/services/runtime/adapter_configuration/session.py +67 -0
  692. ciris_engine/logic/services/runtime/control_service/__init__.py +5 -0
  693. ciris_engine/logic/services/runtime/control_service/service.py +2269 -0
  694. ciris_engine/logic/services/runtime/llm_service/__init__.py +14 -0
  695. ciris_engine/logic/services/runtime/llm_service/pricing_calculator.py +279 -0
  696. ciris_engine/logic/services/runtime/llm_service/service.py +930 -0
  697. ciris_engine/logic/services/tools/__init__.py +5 -0
  698. ciris_engine/logic/services/tools/core_tool_service/__init__.py +8 -0
  699. ciris_engine/logic/services/tools/core_tool_service/service.py +852 -0
  700. ciris_engine/logic/setup/__init__.py +1 -0
  701. ciris_engine/logic/setup/first_run.py +250 -0
  702. ciris_engine/logic/setup/wizard.py +327 -0
  703. ciris_engine/logic/telemetry/__init__.py +46 -0
  704. ciris_engine/logic/telemetry/core.py +239 -0
  705. ciris_engine/logic/telemetry/hot_cold_config.py +133 -0
  706. ciris_engine/logic/telemetry/log_collector.py +190 -0
  707. ciris_engine/logic/telemetry/resource_monitor.py +7 -0
  708. ciris_engine/logic/telemetry/security.py +79 -0
  709. ciris_engine/logic/utils/__init__.py +18 -0
  710. ciris_engine/logic/utils/channel_utils.py +75 -0
  711. ciris_engine/logic/utils/consent/__init__.py +1 -0
  712. ciris_engine/logic/utils/consent/partnership_utils.py +172 -0
  713. ciris_engine/logic/utils/constants.py +92 -0
  714. ciris_engine/logic/utils/context_utils.py +145 -0
  715. ciris_engine/logic/utils/directory_setup.py +533 -0
  716. ciris_engine/logic/utils/graphql_context_provider.py +152 -0
  717. ciris_engine/logic/utils/identity_resolution.py +843 -0
  718. ciris_engine/logic/utils/incident_capture_handler.py +303 -0
  719. ciris_engine/logic/utils/initialization_manager.py +74 -0
  720. ciris_engine/logic/utils/jsondict_helpers.py +290 -0
  721. ciris_engine/logic/utils/log_sanitizer.py +97 -0
  722. ciris_engine/logic/utils/logging_config.py +151 -0
  723. ciris_engine/logic/utils/observability_decorators.py +544 -0
  724. ciris_engine/logic/utils/occurrence_utils.py +155 -0
  725. ciris_engine/logic/utils/path_resolution.py +281 -0
  726. ciris_engine/logic/utils/platform_detection.py +286 -0
  727. ciris_engine/logic/utils/privacy.py +266 -0
  728. ciris_engine/logic/utils/profile_loader.py +124 -0
  729. ciris_engine/logic/utils/profile_manager.py +16 -0
  730. ciris_engine/logic/utils/runtime_utils.py +69 -0
  731. ciris_engine/logic/utils/shutdown_manager.py +107 -0
  732. ciris_engine/logic/utils/task_formatters.py +60 -0
  733. ciris_engine/logic/utils/task_thought_factory.py +404 -0
  734. ciris_engine/logic/utils/thought_utils.py +54 -0
  735. ciris_engine/logic/utils/user_utils.py +70 -0
  736. ciris_engine/protocols/__init__.py +0 -0
  737. ciris_engine/protocols/adapters/__init__.py +35 -0
  738. ciris_engine/protocols/adapters/base.py +149 -0
  739. ciris_engine/protocols/adapters/configurable.py +265 -0
  740. ciris_engine/protocols/adapters/message.py +90 -0
  741. ciris_engine/protocols/audit/__init__.py +1 -0
  742. ciris_engine/protocols/buses/__init__.py +1 -0
  743. ciris_engine/protocols/config/__init__.py +1 -0
  744. ciris_engine/protocols/conscience/__init__.py +1 -0
  745. ciris_engine/protocols/consent.py +88 -0
  746. ciris_engine/protocols/context/__init__.py +1 -0
  747. ciris_engine/protocols/data/__init__.py +1 -0
  748. ciris_engine/protocols/dma/__init__.py +1 -0
  749. ciris_engine/protocols/dma/base.py +107 -0
  750. ciris_engine/protocols/faculties.py +34 -0
  751. ciris_engine/protocols/formatters/__init__.py +1 -0
  752. ciris_engine/protocols/handlers/__init__.py +1 -0
  753. ciris_engine/protocols/infrastructure/__init__.py +25 -0
  754. ciris_engine/protocols/infrastructure/base.py +377 -0
  755. ciris_engine/protocols/persistence/__init__.py +1 -0
  756. ciris_engine/protocols/pipeline_control.py +609 -0
  757. ciris_engine/protocols/processors/__init__.py +19 -0
  758. ciris_engine/protocols/processors/agent.py +299 -0
  759. ciris_engine/protocols/processors/base.py +130 -0
  760. ciris_engine/protocols/processors/orchestration.py +62 -0
  761. ciris_engine/protocols/registries/__init__.py +1 -0
  762. ciris_engine/protocols/runtime/__init__.py +1 -0
  763. ciris_engine/protocols/runtime/base.py +163 -0
  764. ciris_engine/protocols/secrets/__init__.py +1 -0
  765. ciris_engine/protocols/services/__init__.py +80 -0
  766. ciris_engine/protocols/services/adaptation/__init__.py +7 -0
  767. ciris_engine/protocols/services/adaptation/self_observation.py +265 -0
  768. ciris_engine/protocols/services/governance/__init__.py +20 -0
  769. ciris_engine/protocols/services/governance/communication.py +58 -0
  770. ciris_engine/protocols/services/governance/filter.py +56 -0
  771. ciris_engine/protocols/services/governance/visibility.py +32 -0
  772. ciris_engine/protocols/services/governance/wa_auth.py +192 -0
  773. ciris_engine/protocols/services/governance/wise_authority.py +75 -0
  774. ciris_engine/protocols/services/graph/__init__.py +19 -0
  775. ciris_engine/protocols/services/graph/audit.py +92 -0
  776. ciris_engine/protocols/services/graph/config.py +54 -0
  777. ciris_engine/protocols/services/graph/incident_management.py +103 -0
  778. ciris_engine/protocols/services/graph/memory.py +110 -0
  779. ciris_engine/protocols/services/graph/telemetry.py +51 -0
  780. ciris_engine/protocols/services/graph/tsdb_consolidation.py +87 -0
  781. ciris_engine/protocols/services/infrastructure/__init__.py +11 -0
  782. ciris_engine/protocols/services/infrastructure/authentication.py +159 -0
  783. ciris_engine/protocols/services/infrastructure/credit_gate.py +46 -0
  784. ciris_engine/protocols/services/infrastructure/database_maintenance.py +25 -0
  785. ciris_engine/protocols/services/infrastructure/resource_monitor.py +83 -0
  786. ciris_engine/protocols/services/lifecycle/__init__.py +13 -0
  787. ciris_engine/protocols/services/lifecycle/initialization.py +41 -0
  788. ciris_engine/protocols/services/lifecycle/scheduler.py +42 -0
  789. ciris_engine/protocols/services/lifecycle/shutdown.py +50 -0
  790. ciris_engine/protocols/services/lifecycle/time.py +31 -0
  791. ciris_engine/protocols/services/runtime/__init__.py +13 -0
  792. ciris_engine/protocols/services/runtime/llm.py +50 -0
  793. ciris_engine/protocols/services/runtime/runtime_control.py +193 -0
  794. ciris_engine/protocols/services/runtime/secrets.py +100 -0
  795. ciris_engine/protocols/services/runtime/tool.py +123 -0
  796. ciris_engine/protocols/telemetry/__init__.py +1 -0
  797. ciris_engine/protocols/utils/__init__.py +1 -0
  798. ciris_engine/schemas/__init__.py +112 -0
  799. ciris_engine/schemas/actions/__init__.py +37 -0
  800. ciris_engine/schemas/actions/parameters.py +137 -0
  801. ciris_engine/schemas/adapters/__init__.py +13 -0
  802. ciris_engine/schemas/adapters/cirisnode.py +135 -0
  803. ciris_engine/schemas/adapters/cli.py +97 -0
  804. ciris_engine/schemas/adapters/cli_tools.py +98 -0
  805. ciris_engine/schemas/adapters/discord.py +125 -0
  806. ciris_engine/schemas/adapters/graphql_core.py +144 -0
  807. ciris_engine/schemas/adapters/registration.py +47 -0
  808. ciris_engine/schemas/adapters/runtime_context.py +48 -0
  809. ciris_engine/schemas/adapters/tool_execution.py +45 -0
  810. ciris_engine/schemas/adapters/tools.py +96 -0
  811. ciris_engine/schemas/api/__init__.py +1 -0
  812. ciris_engine/schemas/api/agent.py +50 -0
  813. ciris_engine/schemas/api/audit.py +38 -0
  814. ciris_engine/schemas/api/auth.py +351 -0
  815. ciris_engine/schemas/api/config_security.py +242 -0
  816. ciris_engine/schemas/api/emergency.py +111 -0
  817. ciris_engine/schemas/api/responses.py +72 -0
  818. ciris_engine/schemas/api/runtime.py +26 -0
  819. ciris_engine/schemas/api/telemetry.py +109 -0
  820. ciris_engine/schemas/api/wa.py +90 -0
  821. ciris_engine/schemas/audit/__init__.py +13 -0
  822. ciris_engine/schemas/audit/core.py +139 -0
  823. ciris_engine/schemas/audit/hash_chain.py +58 -0
  824. ciris_engine/schemas/audit/verification.py +131 -0
  825. ciris_engine/schemas/buses/__init__.py +1 -0
  826. ciris_engine/schemas/config/__init__.py +41 -0
  827. ciris_engine/schemas/config/agent.py +279 -0
  828. ciris_engine/schemas/config/cognitive_state_behaviors.py +194 -0
  829. ciris_engine/schemas/config/default_dsar_sops.py +178 -0
  830. ciris_engine/schemas/config/essential.py +195 -0
  831. ciris_engine/schemas/config/tickets.py +86 -0
  832. ciris_engine/schemas/conscience/__init__.py +25 -0
  833. ciris_engine/schemas/conscience/context.py +34 -0
  834. ciris_engine/schemas/conscience/core.py +145 -0
  835. ciris_engine/schemas/conscience/results.py +24 -0
  836. ciris_engine/schemas/consent/__init__.py +5 -0
  837. ciris_engine/schemas/consent/core.py +404 -0
  838. ciris_engine/schemas/context/__init__.py +1 -0
  839. ciris_engine/schemas/covenant.py +382 -0
  840. ciris_engine/schemas/data/__init__.py +1 -0
  841. ciris_engine/schemas/dma/__init__.py +16 -0
  842. ciris_engine/schemas/dma/core.py +199 -0
  843. ciris_engine/schemas/dma/faculty.py +192 -0
  844. ciris_engine/schemas/dma/prompts.py +172 -0
  845. ciris_engine/schemas/dma/results.py +103 -0
  846. ciris_engine/schemas/formatters/__init__.py +1 -0
  847. ciris_engine/schemas/handlers/__init__.py +10 -0
  848. ciris_engine/schemas/handlers/context.py +119 -0
  849. ciris_engine/schemas/handlers/contexts.py +100 -0
  850. ciris_engine/schemas/handlers/core.py +167 -0
  851. ciris_engine/schemas/handlers/memory_schemas.py +67 -0
  852. ciris_engine/schemas/handlers/schemas.py +95 -0
  853. ciris_engine/schemas/identity.py +149 -0
  854. ciris_engine/schemas/infrastructure/__init__.py +1 -0
  855. ciris_engine/schemas/infrastructure/base.py +256 -0
  856. ciris_engine/schemas/infrastructure/behavioral_patterns.py +129 -0
  857. ciris_engine/schemas/infrastructure/feedback_loop.py +57 -0
  858. ciris_engine/schemas/infrastructure/identity_variance.py +141 -0
  859. ciris_engine/schemas/infrastructure/oauth.py +175 -0
  860. ciris_engine/schemas/infrastructure/wa_cli_wizard.py +54 -0
  861. ciris_engine/schemas/persistence/__init__.py +34 -0
  862. ciris_engine/schemas/persistence/core.py +140 -0
  863. ciris_engine/schemas/persistence/correlations.py +73 -0
  864. ciris_engine/schemas/persistence/postgres/__init__.py +1 -0
  865. ciris_engine/schemas/persistence/postgres/tables.py +280 -0
  866. ciris_engine/schemas/persistence/sqlite/__init__.py +1 -0
  867. ciris_engine/schemas/persistence/sqlite/tables.py +281 -0
  868. ciris_engine/schemas/platform.py +149 -0
  869. ciris_engine/schemas/processors/__init__.py +26 -0
  870. ciris_engine/schemas/processors/base.py +130 -0
  871. ciris_engine/schemas/processors/cognitive.py +77 -0
  872. ciris_engine/schemas/processors/context.py +35 -0
  873. ciris_engine/schemas/processors/core.py +152 -0
  874. ciris_engine/schemas/processors/dma.py +105 -0
  875. ciris_engine/schemas/processors/error.py +122 -0
  876. ciris_engine/schemas/processors/main.py +109 -0
  877. ciris_engine/schemas/processors/phase_results.py +21 -0
  878. ciris_engine/schemas/processors/results.py +99 -0
  879. ciris_engine/schemas/processors/solitude.py +79 -0
  880. ciris_engine/schemas/processors/state.py +202 -0
  881. ciris_engine/schemas/processors/state_example.py +177 -0
  882. ciris_engine/schemas/processors/states.py +21 -0
  883. ciris_engine/schemas/processors/status.py +34 -0
  884. ciris_engine/schemas/registries/__init__.py +1 -0
  885. ciris_engine/schemas/registries/base.py +66 -0
  886. ciris_engine/schemas/resources/__init__.py +15 -0
  887. ciris_engine/schemas/resources/crisis.py +315 -0
  888. ciris_engine/schemas/runtime/__init__.py +42 -0
  889. ciris_engine/schemas/runtime/adapter_management.py +186 -0
  890. ciris_engine/schemas/runtime/api.py +58 -0
  891. ciris_engine/schemas/runtime/audit.py +50 -0
  892. ciris_engine/schemas/runtime/bootstrap.py +33 -0
  893. ciris_engine/schemas/runtime/contexts.py +61 -0
  894. ciris_engine/schemas/runtime/core.py +161 -0
  895. ciris_engine/schemas/runtime/enums.py +167 -0
  896. ciris_engine/schemas/runtime/extended.py +232 -0
  897. ciris_engine/schemas/runtime/manifest.py +311 -0
  898. ciris_engine/schemas/runtime/memory.py +60 -0
  899. ciris_engine/schemas/runtime/messages.py +108 -0
  900. ciris_engine/schemas/runtime/models.py +156 -0
  901. ciris_engine/schemas/runtime/processing_context.py +43 -0
  902. ciris_engine/schemas/runtime/protocols_core.py +96 -0
  903. ciris_engine/schemas/runtime/resources.py +33 -0
  904. ciris_engine/schemas/runtime/system_context.py +417 -0
  905. ciris_engine/schemas/secrets/__init__.py +1 -0
  906. ciris_engine/schemas/secrets/core.py +267 -0
  907. ciris_engine/schemas/secrets/service.py +95 -0
  908. ciris_engine/schemas/services/__init__.py +33 -0
  909. ciris_engine/schemas/services/audit_summary_node.py +172 -0
  910. ciris_engine/schemas/services/authority/__init__.py +39 -0
  911. ciris_engine/schemas/services/authority/jwt.py +158 -0
  912. ciris_engine/schemas/services/authority/wa_updates.py +138 -0
  913. ciris_engine/schemas/services/authority/wise_authority.py +163 -0
  914. ciris_engine/schemas/services/authority_core.py +370 -0
  915. ciris_engine/schemas/services/capabilities.py +72 -0
  916. ciris_engine/schemas/services/community_core.py +95 -0
  917. ciris_engine/schemas/services/context.py +111 -0
  918. ciris_engine/schemas/services/conversation_summary_node.py +189 -0
  919. ciris_engine/schemas/services/core/__init__.py +153 -0
  920. ciris_engine/schemas/services/core/runtime.py +262 -0
  921. ciris_engine/schemas/services/core/runtime_config.py +117 -0
  922. ciris_engine/schemas/services/core/secrets.py +65 -0
  923. ciris_engine/schemas/services/correlation_node.py +179 -0
  924. ciris_engine/schemas/services/credit_gate.py +92 -0
  925. ciris_engine/schemas/services/discord_nodes.py +299 -0
  926. ciris_engine/schemas/services/feedback_core.py +131 -0
  927. ciris_engine/schemas/services/filters_core.py +270 -0
  928. ciris_engine/schemas/services/governance.py +26 -0
  929. ciris_engine/schemas/services/graph/__init__.py +26 -0
  930. ciris_engine/schemas/services/graph/attributes.py +254 -0
  931. ciris_engine/schemas/services/graph/audit.py +98 -0
  932. ciris_engine/schemas/services/graph/consolidation.py +338 -0
  933. ciris_engine/schemas/services/graph/edge_types.py +43 -0
  934. ciris_engine/schemas/services/graph/edges.py +88 -0
  935. ciris_engine/schemas/services/graph/incident.py +312 -0
  936. ciris_engine/schemas/services/graph/memory.py +84 -0
  937. ciris_engine/schemas/services/graph/node_data.py +174 -0
  938. ciris_engine/schemas/services/graph/query_results.py +82 -0
  939. ciris_engine/schemas/services/graph/telemetry.py +250 -0
  940. ciris_engine/schemas/services/graph/tsdb_consolidation.py +27 -0
  941. ciris_engine/schemas/services/graph/tsdb_models.py +107 -0
  942. ciris_engine/schemas/services/graph_core.py +196 -0
  943. ciris_engine/schemas/services/graph_typed_nodes.py +194 -0
  944. ciris_engine/schemas/services/infrastructure/__init__.py +1 -0
  945. ciris_engine/schemas/services/infrastructure/resource_monitor.py +20 -0
  946. ciris_engine/schemas/services/lifecycle/__init__.py +9 -0
  947. ciris_engine/schemas/services/lifecycle/initialization.py +33 -0
  948. ciris_engine/schemas/services/lifecycle/time.py +50 -0
  949. ciris_engine/schemas/services/llm.py +187 -0
  950. ciris_engine/schemas/services/metadata.py +43 -0
  951. ciris_engine/schemas/services/nodes.py +704 -0
  952. ciris_engine/schemas/services/operations.py +126 -0
  953. ciris_engine/schemas/services/requests.py +128 -0
  954. ciris_engine/schemas/services/resources_core.py +182 -0
  955. ciris_engine/schemas/services/runtime_control.py +1010 -0
  956. ciris_engine/schemas/services/shutdown.py +88 -0
  957. ciris_engine/schemas/services/special/__init__.py +0 -0
  958. ciris_engine/schemas/services/special/self_observation.py +396 -0
  959. ciris_engine/schemas/services/trace_summary_node.py +199 -0
  960. ciris_engine/schemas/services/visibility.py +98 -0
  961. ciris_engine/schemas/streaming/__init__.py +10 -0
  962. ciris_engine/schemas/streaming/reasoning_stream.py +95 -0
  963. ciris_engine/schemas/telemetry/__init__.py +0 -0
  964. ciris_engine/schemas/telemetry/collector.py +67 -0
  965. ciris_engine/schemas/telemetry/core.py +252 -0
  966. ciris_engine/schemas/telemetry/unified.py +59 -0
  967. ciris_engine/schemas/tools.py +72 -0
  968. ciris_engine/schemas/types.py +47 -0
  969. ciris_engine/schemas/utils/__init__.py +1 -0
  970. ciris_engine/schemas/utils/config_validator.py +54 -0
  971. ciris_engine/utils/__init__.py +1 -0
  972. ciris_engine/utils/serialization.py +35 -0
  973. ciris_sdk/__init__.py +124 -0
  974. ciris_sdk/auth_store.py +261 -0
  975. ciris_sdk/client.py +261 -0
  976. ciris_sdk/exceptions.py +73 -0
  977. ciris_sdk/model_types.py +258 -0
  978. ciris_sdk/models.py +354 -0
  979. ciris_sdk/pagination.py +214 -0
  980. ciris_sdk/rate_limiter.py +188 -0
  981. ciris_sdk/setup.py +17 -0
  982. ciris_sdk/telemetry_models.py +257 -0
  983. ciris_sdk/telemetry_responses.py +199 -0
  984. ciris_sdk/transport.py +177 -0
  985. ciris_sdk/websocket.py +400 -0
  986. main.py +766 -0
@@ -0,0 +1,2342 @@
1
+ """
2
+ ciris_engine/runtime/ciris_runtime.py
3
+
4
+ New simplified runtime that properly orchestrates all components.
5
+ """
6
+
7
+ import asyncio
8
+ import logging
9
+ import os
10
+ import time
11
+ from datetime import datetime, timezone
12
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional
13
+
14
+ from ciris_engine.config.ciris_services import get_billing_url
15
+ from ciris_engine.schemas.types import JSONDict
16
+
17
+ if TYPE_CHECKING:
18
+ from ciris_engine.schemas.runtime.bootstrap import RuntimeBootstrapConfig
19
+
20
+ from ciris_engine.logic import persistence
21
+ from ciris_engine.logic.adapters import load_adapter
22
+ from ciris_engine.logic.infrastructure.handlers.action_dispatcher import ActionDispatcher
23
+ from ciris_engine.logic.infrastructure.handlers.handler_registry import build_action_dispatcher
24
+ from ciris_engine.logic.processors import AgentProcessor
25
+ from ciris_engine.logic.registries.base import ServiceRegistry
26
+ from ciris_engine.logic.utils.constants import DEFAULT_NUM_ROUNDS
27
+ from ciris_engine.logic.utils.shutdown_manager import (
28
+ get_shutdown_manager,
29
+ is_global_shutdown_requested,
30
+ wait_for_global_shutdown_async,
31
+ )
32
+ from ciris_engine.protocols.infrastructure.base import BusManagerProtocol
33
+ from ciris_engine.protocols.runtime.base import BaseAdapterProtocol
34
+ from ciris_engine.protocols.services.adaptation.self_observation import SelfObservationServiceProtocol
35
+
36
+ # Governance service protocols
37
+ # Note: WiseAuthorityService doesn't have a unified protocol - it's a complex system with multiple protocols
38
+ from ciris_engine.protocols.services.governance.filter import AdaptiveFilterServiceProtocol
39
+ from ciris_engine.protocols.services.governance.visibility import VisibilityServiceProtocol
40
+ from ciris_engine.protocols.services.graph.audit import AuditServiceProtocol
41
+ from ciris_engine.protocols.services.graph.config import GraphConfigServiceProtocol
42
+ from ciris_engine.protocols.services.graph.incident_management import IncidentManagementServiceProtocol
43
+
44
+ # Graph service protocols
45
+ from ciris_engine.protocols.services.graph.memory import MemoryServiceProtocol
46
+ from ciris_engine.protocols.services.graph.telemetry import TelemetryServiceProtocol
47
+ from ciris_engine.protocols.services.graph.tsdb_consolidation import TSDBConsolidationServiceProtocol
48
+
49
+ # Infrastructure service protocols
50
+ from ciris_engine.protocols.services.infrastructure.authentication import AuthenticationServiceProtocol
51
+ from ciris_engine.protocols.services.infrastructure.database_maintenance import DatabaseMaintenanceServiceProtocol
52
+ from ciris_engine.protocols.services.infrastructure.resource_monitor import ResourceMonitorServiceProtocol
53
+ from ciris_engine.protocols.services.lifecycle.initialization import InitializationServiceProtocol
54
+
55
+ # Lifecycle service protocols
56
+ from ciris_engine.protocols.services.lifecycle.scheduler import TaskSchedulerServiceProtocol
57
+ from ciris_engine.protocols.services.lifecycle.shutdown import ShutdownServiceProtocol
58
+ from ciris_engine.protocols.services.lifecycle.time import TimeServiceProtocol
59
+
60
+ # Runtime service protocols
61
+ from ciris_engine.protocols.services.runtime.llm import LLMServiceProtocol
62
+ from ciris_engine.protocols.services.runtime.runtime_control import RuntimeControlServiceProtocol
63
+ from ciris_engine.protocols.services.runtime.secrets import SecretsServiceProtocol
64
+ from ciris_engine.protocols.services.runtime.tool import ToolServiceProtocol
65
+ from ciris_engine.schemas.adapters import AdapterServiceRegistration
66
+ from ciris_engine.schemas.config.essential import EssentialConfig
67
+ from ciris_engine.schemas.processors.states import AgentState
68
+ from ciris_engine.schemas.runtime.adapter_management import AdapterConfig
69
+ from ciris_engine.schemas.runtime.core import AgentIdentityRoot
70
+ from ciris_engine.schemas.runtime.enums import ServiceType
71
+ from ciris_engine.schemas.services.operations import InitializationPhase
72
+
73
+ from .component_builder import ComponentBuilder
74
+ from .identity_manager import IdentityManager
75
+ from .service_initializer import ServiceInitializer
76
+
77
+ logger = logging.getLogger(__name__)
78
+
79
+ # Domain identifiers for CIRIS proxy services (LLM, billing)
80
+ # Includes legacy ciris.ai and new ciris-services infrastructure
81
+ CIRIS_PROXY_DOMAINS = ("ciris.ai", "ciris-services")
82
+ # Keep single domain for backwards compatibility (tests)
83
+ CIRIS_PROXY_DOMAIN = "ciris.ai"
84
+
85
+
86
+ class CIRISRuntime:
87
+ """
88
+ Main runtime orchestrator for CIRIS Agent.
89
+ Handles initialization of all components and services.
90
+ Implements the RuntimeInterface protocol.
91
+ """
92
+
93
+ def __new__(cls, *args: Any, **kwargs: Any) -> "CIRISRuntime":
94
+ """Custom __new__ to handle CI environment issues."""
95
+ # This fixes a pytest/CI issue where object.__new__ gets called incorrectly
96
+ instance = object.__new__(cls)
97
+ return instance
98
+
99
+ def __init__(
100
+ self,
101
+ adapter_types: List[str],
102
+ essential_config: Optional[EssentialConfig] = None,
103
+ bootstrap: Optional["RuntimeBootstrapConfig"] = None,
104
+ startup_channel_id: Optional[str] = None,
105
+ adapter_configs: Optional[Dict[str, AdapterConfig]] = None,
106
+ **kwargs: Any,
107
+ ) -> None:
108
+ # CRITICAL: Prevent runtime creation during module imports
109
+ import os
110
+
111
+ if os.environ.get("CIRIS_IMPORT_MODE", "").lower() == "true":
112
+ logger.error("CRITICAL: Attempted to create CIRISRuntime during import mode!")
113
+ raise RuntimeError(
114
+ "Cannot create CIRISRuntime during module imports. "
115
+ "This prevents side effects and unwanted process creation. "
116
+ "Call prevent_sideeffects.allow_runtime_creation() before creating runtime."
117
+ )
118
+
119
+ # Import RuntimeBootstrapConfig here to avoid circular imports
120
+ from ciris_engine.schemas.runtime.bootstrap import RuntimeBootstrapConfig
121
+
122
+ # Declare attributes that will be set in _parse_bootstrap_config
123
+ self.essential_config: EssentialConfig
124
+ self.startup_channel_id: str
125
+ self.adapter_configs: Dict[str, AdapterConfig]
126
+ self.modules_to_load: List[str]
127
+ self.debug: bool
128
+ self._preload_tasks: List[Any]
129
+ self.bootstrap: RuntimeBootstrapConfig
130
+
131
+ # Use bootstrap config if provided, otherwise construct from legacy parameters
132
+ self._parse_bootstrap_config(
133
+ bootstrap, essential_config, startup_channel_id, adapter_types, adapter_configs, kwargs
134
+ )
135
+
136
+ self.adapters: List[BaseAdapterProtocol] = []
137
+
138
+ # CRITICAL: Check for mock LLM environment variable
139
+ self._check_mock_llm()
140
+
141
+ # Initialize managers
142
+ self.identity_manager: Optional[IdentityManager] = None
143
+ self.service_initializer = ServiceInitializer(essential_config=essential_config)
144
+ self.component_builder: Optional[ComponentBuilder] = None
145
+ self.agent_processor: Optional["AgentProcessor"] = None
146
+ self._adapter_tasks: List[asyncio.Task[Any]] = []
147
+
148
+ # Load adapters from bootstrap config
149
+ self._load_adapters_from_bootstrap()
150
+
151
+ if not self.adapters:
152
+ raise RuntimeError("No valid adapters specified, shutting down")
153
+
154
+ # Runtime state
155
+ self._initialized = False
156
+ self._shutdown_manager = get_shutdown_manager()
157
+ self._shutdown_event: Optional[asyncio.Event] = None
158
+ self._shutdown_reason: Optional[str] = None
159
+ self._agent_task: Optional[asyncio.Task[Any]] = None
160
+ self._shutdown_complete = False
161
+ self._shutdown_in_progress = False # Set when shutdown has been initiated
162
+
163
+ # Resume protection - prevents SmartStartup from killing server mid-initialization
164
+ self._resume_in_progress = False # Set during resume_from_first_run
165
+ self._resume_started_at: Optional[float] = None # Timestamp for timeout detection
166
+ self._startup_time: float = time.time() # For uptime calculation
167
+
168
+ # Identity - will be loaded during initialization
169
+ self.agent_identity: Optional[AgentIdentityRoot] = None
170
+
171
+ # Properties to access services from the service initializer
172
+ @property
173
+ def service_registry(self) -> Optional[ServiceRegistry]:
174
+ return self.service_initializer.service_registry if self.service_initializer else None
175
+
176
+ @property
177
+ def bus_manager(self) -> Optional[BusManagerProtocol]:
178
+ return self.service_initializer.bus_manager if self.service_initializer else None
179
+
180
+ @property
181
+ def memory_service(self) -> Optional[MemoryServiceProtocol]:
182
+ return self.service_initializer.memory_service if self.service_initializer else None
183
+
184
+ @property
185
+ def resource_monitor(self) -> Optional[ResourceMonitorServiceProtocol]:
186
+ """Access to resource monitor service - CRITICAL for mission-critical systems."""
187
+ return self.service_initializer.resource_monitor_service if self.service_initializer else None
188
+
189
+ @property
190
+ def secrets_service(self) -> Optional[SecretsServiceProtocol]:
191
+ return self.service_initializer.secrets_service if self.service_initializer else None
192
+
193
+ @property
194
+ def wa_auth_system(self) -> Optional[Any]:
195
+ """WiseAuthorityService - complex system without unified protocol."""
196
+ return self.service_initializer.wa_auth_system if self.service_initializer else None
197
+
198
+ @property
199
+ def telemetry_service(self) -> Optional[TelemetryServiceProtocol]:
200
+ return self.service_initializer.telemetry_service if self.service_initializer else None
201
+
202
+ @property
203
+ def llm_service(self) -> Optional[LLMServiceProtocol]:
204
+ return self.service_initializer.llm_service if self.service_initializer else None
205
+
206
+ @property
207
+ def audit_service(self) -> Optional[AuditServiceProtocol]:
208
+ return self.service_initializer.audit_service if self.service_initializer else None
209
+
210
+ @property
211
+ def adaptive_filter_service(self) -> Optional[AdaptiveFilterServiceProtocol]:
212
+ return self.service_initializer.adaptive_filter_service if self.service_initializer else None
213
+
214
+ @property
215
+ def config_manager(self) -> Optional[GraphConfigServiceProtocol]:
216
+ """Return GraphConfigService for RuntimeControlService compatibility."""
217
+ return self.service_initializer.config_service if self.service_initializer else None
218
+
219
+ @property
220
+ def secrets_tool_service(self) -> Optional[ToolServiceProtocol]:
221
+ return self.service_initializer.secrets_tool_service if self.service_initializer else None
222
+
223
+ @property
224
+ def time_service(self) -> Optional[TimeServiceProtocol]:
225
+ return self.service_initializer.time_service if self.service_initializer else None
226
+
227
+ @property
228
+ def config_service(self) -> Optional[GraphConfigServiceProtocol]:
229
+ """Access to configuration service."""
230
+ return self.service_initializer.config_service if self.service_initializer else None
231
+
232
+ @property
233
+ def task_scheduler(self) -> Optional[TaskSchedulerServiceProtocol]:
234
+ """Access to task scheduler service."""
235
+ return self.service_initializer.task_scheduler_service if self.service_initializer else None
236
+
237
+ @property
238
+ def authentication_service(self) -> Optional[AuthenticationServiceProtocol]:
239
+ """Access to authentication service."""
240
+ return self.service_initializer.auth_service if self.service_initializer else None
241
+
242
+ @property
243
+ def incident_management_service(self) -> Optional[IncidentManagementServiceProtocol]:
244
+ """Access to incident management service."""
245
+ return self.service_initializer.incident_management_service if self.service_initializer else None
246
+
247
+ @property
248
+ def runtime_control_service(self) -> Optional[RuntimeControlServiceProtocol]:
249
+ """Access to runtime control service."""
250
+ return self.service_initializer.runtime_control_service if self.service_initializer else None
251
+
252
+ @property
253
+ def profile(self) -> Optional[Any]:
254
+ """Convert agent identity to profile format for compatibility."""
255
+ if not self.agent_identity:
256
+ return None
257
+
258
+ # Create AgentTemplate from identity
259
+ from ciris_engine.schemas.config.agent import AgentTemplate, DSDMAConfiguration
260
+
261
+ # Create DSDMAConfiguration object if needed
262
+ dsdma_config = None
263
+ if (
264
+ self.agent_identity.core_profile.domain_specific_knowledge
265
+ or self.agent_identity.core_profile.dsdma_prompt_template
266
+ ):
267
+ dsdma_config = DSDMAConfiguration(
268
+ domain_specific_knowledge=self.agent_identity.core_profile.domain_specific_knowledge,
269
+ prompt_template=self.agent_identity.core_profile.dsdma_prompt_template,
270
+ )
271
+
272
+ return AgentTemplate(
273
+ name=self.agent_identity.agent_id,
274
+ description=self.agent_identity.core_profile.description,
275
+ role_description=self.agent_identity.core_profile.role_description,
276
+ permitted_actions=self.agent_identity.permitted_actions,
277
+ dsdma_kwargs=dsdma_config,
278
+ csdma_overrides=self.agent_identity.core_profile.csdma_overrides,
279
+ action_selection_pdma_overrides=self.agent_identity.core_profile.action_selection_pdma_overrides,
280
+ )
281
+
282
+ @property
283
+ def maintenance_service(self) -> Optional[DatabaseMaintenanceServiceProtocol]:
284
+ return self.service_initializer.maintenance_service if self.service_initializer else None
285
+
286
+ @property
287
+ def database_maintenance_service(self) -> Optional[DatabaseMaintenanceServiceProtocol]:
288
+ """Alias for maintenance_service - used by API adapter service injection.
289
+
290
+ The API adapter's service configuration expects 'database_maintenance_service'
291
+ while the internal runtime property is named 'maintenance_service'. This alias
292
+ maintains backward compatibility and ensures all 22 core services are accessible.
293
+ """
294
+ return self.maintenance_service
295
+
296
+ @property
297
+ def shutdown_service(self) -> Optional[ShutdownServiceProtocol]:
298
+ """Access to shutdown service."""
299
+ return self.service_initializer.shutdown_service if self.service_initializer else None
300
+
301
+ @property
302
+ def initialization_service(self) -> Optional[InitializationServiceProtocol]:
303
+ """Access to initialization service."""
304
+ return self.service_initializer.initialization_service if self.service_initializer else None
305
+
306
+ @property
307
+ def tsdb_consolidation_service(self) -> Optional[TSDBConsolidationServiceProtocol]:
308
+ """Access to TSDB consolidation service."""
309
+ return self.service_initializer.tsdb_consolidation_service if self.service_initializer else None
310
+
311
+ @property
312
+ def self_observation_service(self) -> Optional[SelfObservationServiceProtocol]:
313
+ """Access to self observation service."""
314
+ return self.service_initializer.self_observation_service if self.service_initializer else None
315
+
316
+ @property
317
+ def visibility_service(self) -> Optional[VisibilityServiceProtocol]:
318
+ """Access to visibility service."""
319
+ return self.service_initializer.visibility_service if self.service_initializer else None
320
+
321
+ @property
322
+ def consent_service(self) -> Optional[Any]:
323
+ """Access to consent service - manages user consent, data retention, and DSAR automation."""
324
+ return self.service_initializer.consent_service if self.service_initializer else None
325
+
326
+ @property
327
+ def agent_template(self) -> Optional[Any]:
328
+ """Access to full agent template - includes tickets config and all template data."""
329
+ return self.identity_manager.agent_template if self.identity_manager else None
330
+
331
+ def _ensure_shutdown_event(self) -> None:
332
+ """Ensure shutdown event is created when needed in async context."""
333
+ if self._shutdown_event is None:
334
+ try:
335
+ self._shutdown_event = asyncio.Event()
336
+ except RuntimeError:
337
+ logger.warning("Cannot create shutdown event outside of async context")
338
+
339
+ def _ensure_config(self) -> EssentialConfig:
340
+ """Ensure essential_config is available, raise if not."""
341
+ if not self.essential_config:
342
+ raise RuntimeError("Essential config not initialized")
343
+ return self.essential_config
344
+
345
+ def request_shutdown(self, reason: str = "Shutdown requested") -> None:
346
+ """Request a graceful shutdown of the runtime."""
347
+ self._ensure_shutdown_event()
348
+
349
+ if self._shutdown_event and self._shutdown_event.is_set():
350
+ logger.debug(f"Shutdown already requested, ignoring duplicate request: {reason}")
351
+ return
352
+
353
+ logger.critical(f"RUNTIME SHUTDOWN REQUESTED: {reason}")
354
+ self._shutdown_reason = reason
355
+
356
+ if self._shutdown_event:
357
+ self._shutdown_event.set()
358
+
359
+ # Use the sync version from shutdown_manager utils to avoid async/await issues
360
+ from ciris_engine.logic.utils.shutdown_manager import request_global_shutdown
361
+
362
+ request_global_shutdown(f"Runtime: {reason}")
363
+
364
+ def _request_shutdown(self, reason: str = "Shutdown requested") -> None:
365
+ """Wrapper used during initialization failures."""
366
+ self.request_shutdown(reason)
367
+
368
+ def set_preload_tasks(self, tasks: List[str]) -> None:
369
+ """Set tasks to be loaded after successful WORK state transition."""
370
+ self._preload_tasks = tasks.copy()
371
+
372
+ async def request_state_transition(self, target_state: str, reason: str) -> bool:
373
+ """Request a cognitive state transition.
374
+
375
+ Args:
376
+ target_state: Target state name (e.g., "DREAM", "PLAY", "SOLITUDE", "WORK")
377
+ reason: Reason for the transition request
378
+
379
+ Returns:
380
+ True if transition was successful, False otherwise
381
+ """
382
+ if not self.agent_processor:
383
+ logger.error("Cannot transition state: agent processor not initialized")
384
+ return False
385
+
386
+ # Convert string to AgentState enum (values are lowercase)
387
+ try:
388
+ target = AgentState(target_state.lower())
389
+ except ValueError:
390
+ logger.error(f"Invalid target state: {target_state}")
391
+ return False
392
+
393
+ current_state = self.agent_processor.state_manager.get_state()
394
+ logger.info(f"State transition requested: {current_state.value} -> {target.value} (reason: {reason})")
395
+
396
+ # Use the state manager's transition_to method
397
+ success = await self.agent_processor.state_manager.transition_to(target)
398
+
399
+ if success:
400
+ logger.info(f"State transition successful: {current_state.value} -> {target.value}")
401
+ else:
402
+ logger.warning(f"State transition failed: {current_state.value} -> {target.value}")
403
+
404
+ return success
405
+
406
+ def get_preload_tasks(self) -> List[str]:
407
+ """Get the list of preload tasks."""
408
+ return self._preload_tasks.copy()
409
+
410
+ async def initialize(self) -> None:
411
+ """Initialize all components and services."""
412
+ if self._initialized:
413
+ return
414
+
415
+ logger.info("Initializing CIRIS Runtime...")
416
+
417
+ try:
418
+ # CRITICAL: Ensure all directories exist with correct permissions BEFORE anything else
419
+ from ciris_engine.logic.utils.directory_setup import (
420
+ DirectorySetupError,
421
+ setup_application_directories,
422
+ validate_directories,
423
+ )
424
+
425
+ try:
426
+ # In production (when running in container), validate only
427
+ # In development, create directories if needed
428
+ import os
429
+
430
+ is_production = os.environ.get("CIRIS_ENV", "dev").lower() == "prod"
431
+
432
+ if is_production:
433
+ logger.info("Production environment detected - validating directories...")
434
+ validate_directories()
435
+ else:
436
+ logger.info("Development environment - setting up directories...")
437
+ setup_application_directories(essential_config=self.essential_config)
438
+
439
+ except DirectorySetupError as e:
440
+ logger.critical(f"DIRECTORY SETUP FAILED: {e}")
441
+ # This will already have printed clear error messages to stderr
442
+ # and potentially exited the process
443
+ raise RuntimeError(f"Cannot start: Directory setup failed - {e}")
444
+
445
+ # First initialize infrastructure services to get the InitializationService instance
446
+ logger.info("[initialize] Initializing infrastructure services...")
447
+ await self.service_initializer.initialize_infrastructure_services()
448
+ logger.info("[initialize] Infrastructure services initialized")
449
+
450
+ # Get the initialization service from service_initializer
451
+ init_manager = self.service_initializer.initialization_service
452
+ if not init_manager:
453
+ raise RuntimeError("InitializationService not available from ServiceInitializer")
454
+ logger.info(f"[initialize] Got initialization service: {init_manager}")
455
+
456
+ # Register all initialization steps with proper phases
457
+ logger.info("[initialize] Registering initialization steps...")
458
+ self._register_initialization_steps(init_manager)
459
+ logger.info("[initialize] Steps registered")
460
+
461
+ # Run the initialization sequence
462
+ logger.info("[initialize] Running initialization sequence...")
463
+ init_result = await init_manager.initialize()
464
+ logger.info(f"[initialize] Initialization sequence result: {init_result}")
465
+
466
+ if not init_result:
467
+ raise RuntimeError("Initialization sequence failed - check logs for details")
468
+
469
+ self._initialized = True
470
+ agent_name = self.agent_identity.agent_id if self.agent_identity else "NO_IDENTITY"
471
+ logger.info(f"CIRIS Runtime initialized successfully with identity '{agent_name}'")
472
+
473
+ except asyncio.TimeoutError as e:
474
+ logger.critical(f"Runtime initialization TIMED OUT: {e}", exc_info=True)
475
+ self._initialized = False
476
+ raise
477
+ except Exception as e:
478
+ logger.critical(f"Runtime initialization failed: {e}", exc_info=True)
479
+ if "maintenance" in str(e).lower():
480
+ logger.critical("Database maintenance failure during initialization - system cannot start safely")
481
+ self._initialized = False
482
+ raise
483
+
484
+ async def _initialize_identity(self) -> None:
485
+ """Initialize agent identity - create from template on first run, load from graph thereafter.
486
+
487
+ In first-run mode, this only creates the IdentityManager but does NOT seed the graph.
488
+ The actual identity seeding happens in resume_from_first_run() AFTER the user selects
489
+ their template in the setup wizard.
490
+ """
491
+ from ciris_engine.logic.setup.first_run import is_first_run
492
+
493
+ config = self._ensure_config()
494
+ if not self.time_service:
495
+ raise RuntimeError("TimeService not available for IdentityManager")
496
+ self.identity_manager = IdentityManager(config, self.time_service)
497
+
498
+ # In first-run mode, skip identity seeding - user hasn't selected template yet
499
+ # Identity will be seeded in resume_from_first_run() after setup completes
500
+ if is_first_run():
501
+ logger.info("First-run mode: Skipping identity seeding (will seed after setup wizard)")
502
+ return
503
+
504
+ self.agent_identity = await self.identity_manager.initialize_identity()
505
+
506
+ # Create startup node for continuity tracking
507
+ await self._create_startup_node()
508
+
509
+ def _register_initialization_steps(self, init_manager: Any) -> None:
510
+ """Register all initialization steps with the initialization manager."""
511
+
512
+ # Phase 0: INFRASTRUCTURE (NEW - must be first)
513
+ init_manager.register_step(
514
+ phase=InitializationPhase.INFRASTRUCTURE,
515
+ name="Initialize Infrastructure Services",
516
+ handler=self._initialize_infrastructure,
517
+ verifier=self._verify_infrastructure,
518
+ critical=True,
519
+ )
520
+
521
+ # Phase 1: DATABASE
522
+ init_manager.register_step(
523
+ phase=InitializationPhase.DATABASE,
524
+ name="Initialize Database",
525
+ handler=self._init_database,
526
+ verifier=self._verify_database_integrity,
527
+ critical=True,
528
+ )
529
+
530
+ # Phase 2: MEMORY
531
+ init_manager.register_step(
532
+ phase=InitializationPhase.MEMORY,
533
+ name="Memory Service",
534
+ handler=self._initialize_memory_service,
535
+ verifier=self._verify_memory_service,
536
+ critical=True,
537
+ )
538
+
539
+ # Phase 3: IDENTITY
540
+ init_manager.register_step(
541
+ phase=InitializationPhase.IDENTITY,
542
+ name="Agent Identity",
543
+ handler=self._initialize_identity,
544
+ verifier=self._verify_identity_integrity,
545
+ critical=True,
546
+ )
547
+
548
+ # Phase 4: SECURITY
549
+ init_manager.register_step(
550
+ phase=InitializationPhase.SECURITY,
551
+ name="Security Services",
552
+ handler=self._initialize_security_services,
553
+ verifier=self._verify_security_services,
554
+ critical=True,
555
+ )
556
+
557
+ # Phase 5: SERVICES
558
+ init_manager.register_step(
559
+ phase=InitializationPhase.SERVICES,
560
+ name="Core Services",
561
+ handler=self._initialize_services,
562
+ verifier=self._verify_core_services,
563
+ critical=True,
564
+ )
565
+
566
+ # Start adapters and wait for critical services
567
+ init_manager.register_step(
568
+ phase=InitializationPhase.SERVICES, name="Start Adapters", handler=self._start_adapters, critical=True
569
+ )
570
+
571
+ # Register adapter services immediately after adapters start
572
+ # This ensures communication and other adapter services are available before components build
573
+ init_manager.register_step(
574
+ phase=InitializationPhase.SERVICES,
575
+ name="Register Adapter Services",
576
+ handler=self._register_adapter_services,
577
+ critical=True,
578
+ )
579
+
580
+ # Initialize maintenance service and perform cleanup BEFORE components
581
+ init_manager.register_step(
582
+ phase=InitializationPhase.SERVICES,
583
+ name="Initialize Maintenance Service",
584
+ handler=self._initialize_maintenance_service,
585
+ critical=True,
586
+ )
587
+
588
+ # Adapter connections will be started in COMPONENTS phase after services are ready
589
+
590
+ # Phase 6: COMPONENTS
591
+ init_manager.register_step(
592
+ phase=InitializationPhase.COMPONENTS, name="Build Components", handler=self._build_components, critical=True
593
+ )
594
+
595
+ # Start adapter connections FIRST to establish Discord connection
596
+ init_manager.register_step(
597
+ phase=InitializationPhase.COMPONENTS,
598
+ name="Start Adapter Connections",
599
+ handler=self._start_adapter_connections,
600
+ critical=True,
601
+ timeout=45.0,
602
+ )
603
+
604
+ # Adapter services are now registered inside _start_adapter_connections
605
+ # after waiting for adapters to be healthy
606
+
607
+ # Phase 7: VERIFICATION
608
+ init_manager.register_step(
609
+ phase=InitializationPhase.VERIFICATION,
610
+ name="Final System Verification",
611
+ handler=self._final_verification,
612
+ critical=True,
613
+ )
614
+
615
+ async def _initialize_infrastructure(self) -> None: # NOSONAR: Part of async initialization chain
616
+ """Initialize infrastructure services that all other services depend on."""
617
+ # Infrastructure services already initialized in initialize() method
618
+
619
+ # CRITICAL: File logging is REQUIRED for production
620
+ # FAIL FAST AND LOUD if we can't set it up
621
+ import os
622
+
623
+ if not os.environ.get("PYTEST_CURRENT_TEST"):
624
+ from ciris_engine.logic.utils.logging_config import setup_basic_logging
625
+
626
+ # Get TimeService from service initializer
627
+ time_service = self.service_initializer.time_service
628
+ if not time_service:
629
+ error_msg = "CRITICAL: TimeService not available - CANNOT INITIALIZE FILE LOGGING"
630
+ logger.critical(error_msg)
631
+ raise RuntimeError(error_msg)
632
+
633
+ try:
634
+ setup_basic_logging(
635
+ level=logging.DEBUG if self.debug else logging.INFO,
636
+ log_to_file=True,
637
+ console_output=False, # Already logging to console from main.py
638
+ enable_incident_capture=True,
639
+ time_service=time_service,
640
+ # log_dir defaults to None, which uses path_resolution.get_logs_dir()
641
+ )
642
+ logger.info("[_initialize_infrastructure] File logging initialized successfully")
643
+ except Exception as e:
644
+ error_msg = f"CRITICAL: Failed to setup file logging: {e}"
645
+ logger.critical(error_msg)
646
+ raise RuntimeError(error_msg)
647
+ else:
648
+ logger.debug("[_initialize_infrastructure] Test mode detected, skipping file logging setup")
649
+
650
+ async def _verify_infrastructure(self) -> bool:
651
+ """Verify infrastructure services are operational."""
652
+ # Check that all infrastructure services are running
653
+ if not self.service_initializer.time_service:
654
+ logger.error("TimeService not initialized")
655
+ return False
656
+ if not self.service_initializer.shutdown_service:
657
+ logger.error("ShutdownService not initialized")
658
+ return False
659
+ if not self.service_initializer.initialization_service:
660
+ logger.error("InitializationService not initialized")
661
+ return False
662
+ return True
663
+
664
+ async def _init_database(self) -> None:
665
+ """Initialize database and run migrations."""
666
+ # Use environment-based database URL if set, otherwise use SQLite path from config
667
+ # This allows PostgreSQL support via CIRIS_DB_URL environment variable
668
+ from ciris_engine.logic.persistence.db.dialect import get_adapter
669
+
670
+ adapter = get_adapter()
671
+ if adapter.is_postgresql():
672
+ # PostgreSQL: Use None to trigger environment-based connection
673
+ db_path = None
674
+ logger.info("Using PostgreSQL database from environment (CIRIS_DB_URL)")
675
+ else:
676
+ # SQLite: Use direct path from essential_config to avoid config service dependency
677
+ db_path = str(self.essential_config.database.main_db)
678
+ logger.info(f"Using SQLite database: {db_path}")
679
+
680
+ persistence.initialize_database(db_path)
681
+ persistence.run_migrations(db_path)
682
+
683
+ if not self.essential_config:
684
+ # Use default essential config if none provided
685
+ self.essential_config = EssentialConfig()
686
+ self.essential_config.load_env_vars() # Load CIRIS_DB_URL and other env vars
687
+ logger.warning("No config provided, using defaults")
688
+
689
+ async def _verify_database_integrity(self) -> bool:
690
+ """Verify database integrity before proceeding."""
691
+ try:
692
+ from ciris_engine.logic.persistence.db.dialect import get_adapter
693
+
694
+ adapter = get_adapter()
695
+ # Use environment-based connection for PostgreSQL, direct path for SQLite
696
+ db_path = None if adapter.is_postgresql() else str(self.essential_config.database.main_db)
697
+ conn = persistence.get_db_connection(db_path)
698
+ cursor = conn.cursor()
699
+
700
+ adapter = get_adapter()
701
+ required_tables = ["tasks", "thoughts", "graph_nodes", "graph_edges"]
702
+
703
+ for table in required_tables:
704
+ # Use database-specific query
705
+ if adapter.is_postgresql():
706
+ cursor.execute(
707
+ "SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_name=%s",
708
+ (table,),
709
+ )
710
+ else:
711
+ cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table,))
712
+
713
+ if not cursor.fetchone():
714
+ raise RuntimeError(f"Required table '{table}' missing from database")
715
+
716
+ conn.close()
717
+ logger.info("✓ Database integrity verified")
718
+ return True
719
+ except Exception as e:
720
+ logger.error(f"Database integrity check failed: {e}")
721
+ return False
722
+
723
+ async def _initialize_memory_service(self) -> None:
724
+ """Initialize memory service early for identity storage."""
725
+ config = self._ensure_config()
726
+ await self.service_initializer.initialize_memory_service(config)
727
+
728
+ async def _verify_memory_service(self) -> bool:
729
+ """Verify memory service is operational."""
730
+ return await self.service_initializer.verify_memory_service()
731
+
732
+ async def _verify_identity_integrity(self) -> bool:
733
+ """Verify identity was properly established.
734
+
735
+ In first-run mode, identity is not seeded yet (waiting for user to select template),
736
+ so we only verify that the identity manager was created.
737
+ """
738
+ from ciris_engine.logic.setup.first_run import is_first_run
739
+
740
+ if not self.identity_manager:
741
+ logger.error("Identity manager not initialized")
742
+ return False
743
+
744
+ # In first-run mode, identity isn't seeded yet - just verify manager exists
745
+ if is_first_run():
746
+ logger.info("First-run mode: Identity manager created (identity will be seeded after setup)")
747
+ return True
748
+
749
+ return await self.identity_manager.verify_identity_integrity()
750
+
751
+ async def _initialize_security_services(self) -> None:
752
+ """Initialize security-critical services first."""
753
+ config = self._ensure_config()
754
+ await self.service_initializer.initialize_security_services(config, self.essential_config)
755
+
756
+ async def _verify_security_services(self) -> bool:
757
+ """Verify security services are operational."""
758
+ return await self.service_initializer.verify_security_services()
759
+
760
+ async def _initialize_services(self) -> None:
761
+ """Initialize all remaining core services.
762
+
763
+ In first-run mode, identity is not yet established (user selects template in setup wizard).
764
+ We skip full service initialization - only the API adapter runs for the setup wizard.
765
+ """
766
+ from ciris_engine.logic.setup.first_run import is_first_run
767
+
768
+ config = self._ensure_config()
769
+
770
+ # In first-run mode, skip service initialization - we only need the API server
771
+ if is_first_run():
772
+ logger.info("First-run mode: Skipping core service initialization (setup wizard only)")
773
+ return
774
+
775
+ # Identity MUST be established before services can be initialized
776
+ if not self.agent_identity:
777
+ raise RuntimeError("CRITICAL: Cannot initialize services without agent identity")
778
+ await self.service_initializer.initialize_all_services(
779
+ config, self.essential_config, self.agent_identity.agent_id, self.startup_channel_id, self.modules_to_load
780
+ )
781
+
782
+ # Load any external modules (e.g. mockllm)
783
+ if self.modules_to_load:
784
+ logger.info(f"Loading {len(self.modules_to_load)} external modules: {self.modules_to_load}")
785
+ await self.service_initializer.load_modules(self.modules_to_load)
786
+
787
+ # Set runtime on audit service so it can create trace correlations
788
+ if self.audit_service:
789
+ self.audit_service._runtime = self # type: ignore[attr-defined]
790
+ logger.debug("Set runtime reference on audit service for trace correlations")
791
+
792
+ # Set runtime on visibility service so it can access telemetry for traces
793
+ if self.visibility_service:
794
+ self.visibility_service._runtime = self # type: ignore[attr-defined]
795
+ logger.debug("Set runtime reference on visibility service for trace retrieval")
796
+
797
+ # Update runtime control service with runtime reference
798
+ if self.runtime_control_service:
799
+ if hasattr(self.runtime_control_service, "_set_runtime"):
800
+ self.runtime_control_service._set_runtime(self)
801
+ else:
802
+ self.runtime_control_service.runtime = self # type: ignore[attr-defined]
803
+ logger.info("Updated runtime control service with runtime reference")
804
+
805
+ # Update telemetry service with runtime reference for aggregator
806
+ if self.telemetry_service:
807
+ if hasattr(self.telemetry_service, "_set_runtime"):
808
+ self.telemetry_service._set_runtime(self)
809
+ logger.info("Updated telemetry service with runtime reference for aggregator")
810
+
811
+ async def _verify_core_services(self) -> bool:
812
+ """Verify all core services are operational.
813
+
814
+ In first-run mode, services aren't initialized yet - just return True.
815
+ """
816
+ from ciris_engine.logic.setup.first_run import is_first_run
817
+
818
+ if is_first_run():
819
+ logger.info("First-run mode: Core services verification skipped")
820
+ return True
821
+
822
+ return self.service_initializer.verify_core_services()
823
+
824
+ async def _initialize_maintenance_service(self) -> None:
825
+ """Initialize the maintenance service and perform startup cleanup.
826
+
827
+ In first-run mode, services aren't initialized - skip maintenance.
828
+ """
829
+ from ciris_engine.logic.setup.first_run import is_first_run
830
+
831
+ if is_first_run():
832
+ logger.info("First-run mode: Skipping maintenance service initialization")
833
+ return
834
+
835
+ # Verify maintenance service is available
836
+ if not self.maintenance_service:
837
+ raise RuntimeError("Maintenance service was not initialized properly")
838
+ logger.info("Maintenance service verified available")
839
+
840
+ # Perform startup maintenance to clean stale tasks
841
+ await self._perform_startup_maintenance()
842
+
843
+ async def _start_adapters(self) -> None:
844
+ """Start all adapters."""
845
+ await asyncio.gather(*(adapter.start() for adapter in self.adapters))
846
+ logger.info(f"All {len(self.adapters)} adapters started")
847
+
848
+ # Migrate adapter configurations to graph config
849
+ await self._migrate_adapter_configs_to_graph()
850
+
851
+ async def _wait_for_critical_services(self, timeout: float) -> None:
852
+ """Wait for services required for agent operation."""
853
+ from ciris_engine.schemas.runtime.enums import ServiceType
854
+
855
+ start_time = asyncio.get_event_loop().time()
856
+ last_report_time = start_time
857
+
858
+ required_services = [
859
+ (ServiceType.COMMUNICATION, ["send_message"], "Communication (Discord/API/CLI)"),
860
+ ]
861
+
862
+ while (asyncio.get_event_loop().time() - start_time) < timeout:
863
+ all_ready = True
864
+ missing_services = []
865
+
866
+ for service_type, capabilities, name in required_services:
867
+ if self.service_registry:
868
+ service = await self.service_registry.get_service(
869
+ handler="SpeakHandler", # Use a handler that requires communication
870
+ service_type=service_type,
871
+ required_capabilities=capabilities,
872
+ )
873
+ if not service:
874
+ all_ready = False
875
+ missing_services.append(name)
876
+ else:
877
+ # Check if service is actually healthy (connected)
878
+ if hasattr(service, "is_healthy"):
879
+ is_healthy = await service.is_healthy()
880
+ if not is_healthy:
881
+ all_ready = False
882
+ missing_services.append(f"{name} (registered but not connected)")
883
+ else:
884
+ # Report Discord connection details
885
+ service_name = service.__class__.__name__ if service else "Unknown"
886
+ if "Discord" in service_name and not hasattr(self, "_discord_connected_reported"):
887
+ # Get Discord client info
888
+ if (
889
+ hasattr(service, "client")
890
+ and service.client
891
+ and hasattr(service.client, "user")
892
+ ):
893
+ user = service.client.user
894
+ guilds = service.client.guilds if hasattr(service.client, "guilds") else []
895
+ logger.info(f" ✓ Discord connected as {user} to {len(guilds)} guild(s)")
896
+ for guild in guilds[:3]: # Show first 3 guilds
897
+ logger.info(f" - {guild.name} (ID: {guild.id})")
898
+ if len(guilds) > 3:
899
+ logger.info(f" ... and {len(guilds) - 3} more guild(s)")
900
+ self._discord_connected_reported = True
901
+
902
+ if all_ready:
903
+ return
904
+
905
+ # Report progress every 3 seconds
906
+ current_time = asyncio.get_event_loop().time()
907
+ if current_time - last_report_time >= 3.0:
908
+ elapsed = current_time - start_time
909
+ logger.info(f" ⏳ Still waiting for: {', '.join(missing_services)} ({elapsed:.1f}s elapsed)")
910
+ last_report_time = current_time
911
+
912
+ await asyncio.sleep(0.5)
913
+
914
+ # Timeout reached
915
+ raise TimeoutError(f"Critical services not available after {timeout}s. Missing: {', '.join(missing_services)}")
916
+
917
+ async def _migrate_adapter_configs_to_graph(self) -> None:
918
+ """Migrate adapter configurations to graph config service."""
919
+ if not self.service_initializer or not self.service_initializer.config_service:
920
+ logger.warning("Cannot migrate adapter configs - GraphConfigService not available")
921
+ return
922
+
923
+ config_service = self.service_initializer.config_service
924
+
925
+ # Migrate bootstrap adapter configs
926
+ for adapter_type, adapter_config in self.adapter_configs.items():
927
+ try:
928
+ # Determine adapter ID (handle instance-specific types like "api:8081")
929
+ if ":" in adapter_type:
930
+ base_type, instance_id = adapter_type.split(":", 1)
931
+ adapter_id = f"{base_type}_{instance_id}"
932
+ else:
933
+ # For bootstrap adapters without instance ID, use a standard naming
934
+ adapter_id = f"{adapter_type}_bootstrap"
935
+
936
+ # Store the full config object
937
+ await config_service.set_config(
938
+ key=f"adapter.{adapter_id}.config",
939
+ value=adapter_config.model_dump() if hasattr(adapter_config, "model_dump") else adapter_config,
940
+ updated_by="system_bootstrap",
941
+ )
942
+
943
+ # Also store individual config values for easy access
944
+ config_dict = adapter_config.model_dump() if hasattr(adapter_config, "model_dump") else adapter_config
945
+ if isinstance(config_dict, dict):
946
+ for key, value in config_dict.items():
947
+ await config_service.set_config(
948
+ key=f"adapter.{adapter_id}.{key}", value=value, updated_by="system_bootstrap"
949
+ )
950
+
951
+ logger.info(f"Migrated adapter config for {adapter_id} to graph")
952
+
953
+ except Exception as e:
954
+ logger.error(f"Failed to migrate adapter config for {adapter_type}: {e}")
955
+
956
+ # Migrate tickets config from template (first-run only)
957
+ await self._migrate_tickets_config_to_graph()
958
+
959
+ # Migrate cognitive state behaviors (pre-1.7 compatibility)
960
+ await self._migrate_cognitive_state_behaviors_to_graph()
961
+
962
+ async def _migrate_tickets_config_to_graph(self) -> None:
963
+ """Migrate tickets config to graph.
964
+
965
+ This handles two scenarios:
966
+ 1. First-run: Seeds tickets config from template to graph
967
+ 2. Pre-1.7.0 upgrade: Adds default DSAR SOPs for existing agents without tickets config
968
+
969
+ After migration, tickets.py retrieves config from graph, not template.
970
+ """
971
+ if not self.service_initializer or not self.service_initializer.config_service:
972
+ logger.warning("Cannot migrate tickets config - GraphConfigService not available")
973
+ return
974
+
975
+ config_service = self.service_initializer.config_service
976
+
977
+ # Check if tickets config already exists in graph
978
+ try:
979
+ existing_config = await config_service.get_config("tickets")
980
+ if existing_config and existing_config.value and existing_config.value.dict_value:
981
+ logger.debug("Tickets config already exists in graph - skipping migration")
982
+ return
983
+ except Exception:
984
+ pass # Config doesn't exist, proceed with migration
985
+
986
+ # Try to get tickets config from template (first-run scenario)
987
+ tickets_config = None
988
+ if self.identity_manager and self.identity_manager.agent_template:
989
+ tickets_config = self.identity_manager.agent_template.tickets
990
+
991
+ # If no template available (pre-1.7.0 agent upgrade), create default DSAR SOPs
992
+ if not tickets_config:
993
+ logger.info("No tickets config found - creating default DSAR SOPs for pre-1.7.0 compatibility")
994
+ from ciris_engine.schemas.config.default_dsar_sops import DEFAULT_DSAR_SOPS
995
+ from ciris_engine.schemas.config.tickets import TicketsConfig
996
+
997
+ tickets_config = TicketsConfig(enabled=True, sops=DEFAULT_DSAR_SOPS)
998
+
999
+ try:
1000
+ # Store tickets config as a dict in the graph with IDENTITY scope (WA-protected)
1001
+ from ciris_engine.schemas.services.graph_core import GraphScope
1002
+
1003
+ await config_service.set_config(
1004
+ key="tickets",
1005
+ value=tickets_config.model_dump(),
1006
+ updated_by="system_bootstrap",
1007
+ scope=GraphScope.IDENTITY, # Protected - agent cannot modify
1008
+ )
1009
+ logger.info("Migrated tickets config to graph (IDENTITY scope - WA-protected)")
1010
+ except Exception as e:
1011
+ logger.error(f"Failed to migrate tickets config to graph: {e}")
1012
+
1013
+ def _should_skip_cognitive_migration(self, force_from_template: bool) -> bool:
1014
+ """Check if cognitive migration should be skipped (first-run mode without force)."""
1015
+ from ciris_engine.logic.setup.first_run import is_first_run
1016
+
1017
+ if is_first_run() and not force_from_template:
1018
+ logger.info("[COGNITIVE_MIGRATION] First-run mode: Skipping migration (will seed after setup wizard)")
1019
+ return True
1020
+ return False
1021
+
1022
+ async def _check_existing_cognitive_config(self, config_service: Any) -> bool:
1023
+ """Check if cognitive config already exists in graph.
1024
+
1025
+ Returns True if config exists and should skip migration.
1026
+ """
1027
+ try:
1028
+ existing_config = await config_service.get_config("cognitive_state_behaviors")
1029
+ if existing_config and existing_config.value and existing_config.value.dict_value:
1030
+ existing_wakeup = existing_config.value.dict_value.get("wakeup", {})
1031
+ logger.info(
1032
+ f"[COGNITIVE_MIGRATION] Config already exists in graph - wakeup.enabled={existing_wakeup.get('enabled', 'MISSING')}"
1033
+ )
1034
+ logger.info("[COGNITIVE_MIGRATION] Skipping migration (existing config preserved)")
1035
+ return True
1036
+ except Exception as e:
1037
+ logger.info(f"[COGNITIVE_MIGRATION] No existing config in graph (will migrate): {e}")
1038
+ return False
1039
+
1040
+ def _get_cognitive_behaviors_from_template(self) -> Optional[Any]:
1041
+ """Get cognitive behaviors from the agent template if available."""
1042
+ logger.info(f"[COGNITIVE_MIGRATION] identity_manager={self.identity_manager is not None}")
1043
+ if not self.identity_manager or not self.identity_manager.agent_template:
1044
+ logger.info("[COGNITIVE_MIGRATION] No template available (identity_manager or agent_template is None)")
1045
+ return None
1046
+
1047
+ template = self.identity_manager.agent_template
1048
+ logger.info(f"[COGNITIVE_MIGRATION] Template loaded: name={getattr(template, 'name', 'UNKNOWN')}")
1049
+ cognitive_behaviors = getattr(template, "cognitive_state_behaviors", None)
1050
+ if cognitive_behaviors:
1051
+ logger.info(
1052
+ f"[COGNITIVE_MIGRATION] Template has cognitive_state_behaviors: wakeup.enabled={cognitive_behaviors.wakeup.enabled}"
1053
+ )
1054
+ else:
1055
+ logger.info("[COGNITIVE_MIGRATION] Template has NO cognitive_state_behaviors attribute")
1056
+ return cognitive_behaviors
1057
+
1058
+ def _create_legacy_cognitive_behaviors(self) -> Any:
1059
+ """Create pre-1.7 compatible cognitive behaviors config."""
1060
+ from ciris_engine.schemas.config.cognitive_state_behaviors import (
1061
+ CognitiveStateBehaviors,
1062
+ DreamBehavior,
1063
+ StateBehavior,
1064
+ StatePreservationBehavior,
1065
+ )
1066
+
1067
+ logger.info("No cognitive state behaviors found - creating pre-1.7 compatible config")
1068
+ return CognitiveStateBehaviors(
1069
+ play=StateBehavior(
1070
+ enabled=False,
1071
+ rationale="Pre-1.7 agent: PLAY state not available in legacy version",
1072
+ ),
1073
+ dream=DreamBehavior(
1074
+ enabled=False,
1075
+ auto_schedule=False,
1076
+ rationale="Pre-1.7 agent: DREAM state not available in legacy version",
1077
+ ),
1078
+ solitude=StateBehavior(
1079
+ enabled=False,
1080
+ rationale="Pre-1.7 agent: SOLITUDE state not available in legacy version",
1081
+ ),
1082
+ state_preservation=StatePreservationBehavior(
1083
+ enabled=True,
1084
+ resume_silently=False,
1085
+ rationale="Pre-1.7 agent: preserve state across restarts",
1086
+ ),
1087
+ )
1088
+
1089
+ async def _save_cognitive_behaviors_to_graph(self, config_service: Any, cognitive_behaviors: Any) -> None:
1090
+ """Save cognitive behaviors to the graph with IDENTITY scope."""
1091
+ from ciris_engine.schemas.services.graph_core import GraphScope
1092
+
1093
+ config_dict = cognitive_behaviors.model_dump()
1094
+ logger.info(
1095
+ f"[COGNITIVE_MIGRATION] Saving to graph: wakeup.enabled={config_dict.get('wakeup', {}).get('enabled', 'MISSING')}"
1096
+ )
1097
+ await config_service.set_config(
1098
+ key="cognitive_state_behaviors",
1099
+ value=config_dict,
1100
+ updated_by="system_bootstrap",
1101
+ scope=GraphScope.IDENTITY,
1102
+ )
1103
+ logger.info("[COGNITIVE_MIGRATION] SUCCESS - Migrated cognitive state behaviors to graph (IDENTITY scope)")
1104
+
1105
+ async def _migrate_cognitive_state_behaviors_to_graph(self, force_from_template: bool = False) -> None:
1106
+ """Migrate cognitive state behaviors to graph.
1107
+
1108
+ This handles two scenarios:
1109
+ 1. First-run: Seeds cognitive behaviors from template to graph
1110
+ 2. Pre-1.7.0 upgrade: Adds legacy-compatible behaviors (PLAY/DREAM/SOLITUDE disabled)
1111
+
1112
+ Pre-1.7 agents get:
1113
+ - Wakeup: enabled (full identity ceremony)
1114
+ - Shutdown: always_consent (Covenant compliance)
1115
+ - Play/Dream/Solitude: DISABLED (these states didn't exist pre-1.7)
1116
+
1117
+ After migration, StateManager retrieves config from graph, not template.
1118
+
1119
+ Args:
1120
+ force_from_template: If True, always seed from template (used during resume_from_first_run
1121
+ when template is now available). This overwrites any pre-existing config.
1122
+ """
1123
+ if self._should_skip_cognitive_migration(force_from_template):
1124
+ return
1125
+
1126
+ if not self.service_initializer or not self.service_initializer.config_service:
1127
+ logger.warning("[COGNITIVE_MIGRATION] Cannot migrate - GraphConfigService not available")
1128
+ return
1129
+
1130
+ config_service = self.service_initializer.config_service
1131
+
1132
+ logger.info("[COGNITIVE_MIGRATION] Starting cognitive state behaviors migration check...")
1133
+ logger.info(f"[COGNITIVE_MIGRATION] force_from_template={force_from_template}")
1134
+
1135
+ if not force_from_template:
1136
+ if await self._check_existing_cognitive_config(config_service):
1137
+ return
1138
+ else:
1139
+ logger.info("[COGNITIVE_MIGRATION] Force mode: Will overwrite existing config with template values")
1140
+
1141
+ # Try to get cognitive behaviors from template
1142
+ cognitive_behaviors = self._get_cognitive_behaviors_from_template()
1143
+
1144
+ # If no template available, use Covenant-compliant defaults (all states enabled)
1145
+ # This applies to fresh installs without templates (e.g., QA testing, API-only mode)
1146
+ # Note: The old pre-1.7 upgrade logic disabled PLAY/DREAM/SOLITUDE, but this was
1147
+ # overly conservative. Default behavior should enable all states - users can disable
1148
+ # specific states via template configuration if needed.
1149
+ if not cognitive_behaviors:
1150
+ from ciris_engine.schemas.config.cognitive_state_behaviors import CognitiveStateBehaviors
1151
+
1152
+ logger.info("[COGNITIVE_MIGRATION] No template - using Covenant-compliant defaults (all states enabled)")
1153
+ cognitive_behaviors = CognitiveStateBehaviors()
1154
+
1155
+ try:
1156
+ await self._save_cognitive_behaviors_to_graph(config_service, cognitive_behaviors)
1157
+ except Exception as e:
1158
+ logger.error(f"[COGNITIVE_MIGRATION] FAILED to migrate cognitive state behaviors to graph: {e}")
1159
+
1160
+ async def _final_verification(self) -> None:
1161
+ """Perform final system verification.
1162
+
1163
+ In first-run mode, identity isn't established yet - skip full verification.
1164
+ """
1165
+ from ciris_engine.logic.setup.first_run import is_first_run
1166
+
1167
+ # In first-run mode, identity isn't established yet
1168
+ if is_first_run():
1169
+ logger.info("First-run mode: Skipping final verification (waiting for setup wizard)")
1170
+ logger.info("=" * 60)
1171
+ logger.info("CIRIS Agent First-Run Mode Active")
1172
+ logger.info("Setup wizard is ready at http://127.0.0.1:8080/setup")
1173
+ logger.info("=" * 60)
1174
+ return
1175
+
1176
+ # Don't check initialization status here - we're still IN the initialization process
1177
+ # Just verify the critical components are ready
1178
+
1179
+ # Verify identity loaded
1180
+ if not self.agent_identity:
1181
+ raise RuntimeError("No agent identity established")
1182
+
1183
+ # Log final status
1184
+ logger.info("=" * 60)
1185
+ logger.info("CIRIS Agent Pre-Wakeup Verification Complete")
1186
+ logger.info(f"Identity: {self.agent_identity.agent_id}")
1187
+ logger.info(f"Purpose: {self.agent_identity.core_profile.description}")
1188
+ logger.info(f"Capabilities: {len(self.agent_identity.permitted_actions)} allowed")
1189
+ # Count all registered services
1190
+ service_count = 0
1191
+ if self.service_registry:
1192
+ registry_info = self.service_registry.get_provider_info()
1193
+ # Count services from the 'services' key (new structure)
1194
+ for service_list in registry_info.get("services", {}).values():
1195
+ service_count += len(service_list)
1196
+
1197
+ logger.info(f"Services: {service_count} registered")
1198
+ logger.info("=" * 60)
1199
+
1200
+ async def _perform_startup_maintenance(self) -> None:
1201
+ """Perform database cleanup at startup."""
1202
+ if self.maintenance_service:
1203
+ try:
1204
+ logger.info("Starting critical database maintenance...")
1205
+ await self.maintenance_service.perform_startup_cleanup()
1206
+ logger.info("Database maintenance completed successfully")
1207
+ except Exception as e:
1208
+ logger.critical(f"CRITICAL ERROR: Database maintenance failed during startup: {e}")
1209
+ logger.critical("Database integrity cannot be guaranteed - initiating graceful shutdown")
1210
+ self._request_shutdown(f"Critical database maintenance failure: {e}")
1211
+ raise RuntimeError(f"Database maintenance failure: {e}") from e
1212
+ else:
1213
+ logger.critical("CRITICAL ERROR: No maintenance service available during startup")
1214
+ logger.critical("Database integrity cannot be guaranteed - initiating graceful shutdown")
1215
+ self._request_shutdown("No maintenance service available")
1216
+ raise RuntimeError("No maintenance service available")
1217
+
1218
+ async def _clean_runtime_configs(self) -> None:
1219
+ """Clean up runtime-specific configuration from previous runs."""
1220
+ if not self.config_service:
1221
+ logger.warning("Config service not available - skipping runtime config cleanup")
1222
+ return
1223
+
1224
+ try:
1225
+ logger.info("Cleaning up runtime-specific configurations...")
1226
+
1227
+ # Get all config entries
1228
+ all_configs = await self.config_service.list_configs()
1229
+
1230
+ runtime_config_patterns = [
1231
+ "adapter.", # Adapter configurations
1232
+ "runtime.", # Runtime-specific settings
1233
+ "session.", # Session-specific data
1234
+ "temp.", # Temporary configurations
1235
+ ]
1236
+
1237
+ deleted_count = 0
1238
+
1239
+ for key, value in all_configs.items():
1240
+ # Check if this is a runtime-specific config
1241
+ is_runtime_config = any(key.startswith(pattern) for pattern in runtime_config_patterns)
1242
+
1243
+ if is_runtime_config:
1244
+ # Get the actual config node to check if it should be deleted
1245
+ config_node = await self.config_service.get_config(key)
1246
+ if config_node:
1247
+ # Skip configs created by system_bootstrap (essential configs)
1248
+ if config_node.updated_by == "system_bootstrap":
1249
+ logger.debug(f"Preserving bootstrap config: {key}")
1250
+ continue
1251
+
1252
+ # Convert to GraphNode and use memory service to forget it
1253
+ graph_node = config_node.to_graph_node()
1254
+ await self.config_service.graph.forget(graph_node) # type: ignore[attr-defined]
1255
+ deleted_count += 1
1256
+ logger.debug(f"Deleted runtime config node: {key}")
1257
+
1258
+ if deleted_count > 0:
1259
+ logger.info(f"Cleaned up {deleted_count} runtime-specific configuration entries from previous runs")
1260
+ else:
1261
+ logger.info("No runtime-specific configuration entries to clean up")
1262
+
1263
+ except Exception as e:
1264
+ logger.error(f"Failed to clean up runtime config: {e}", exc_info=True)
1265
+ # Non-critical - don't fail initialization
1266
+
1267
+ async def _register_adapter_services(self) -> None:
1268
+ """Register services provided by the loaded adapters.
1269
+
1270
+ In first-run mode, skip registration since services aren't initialized.
1271
+ """
1272
+ from ciris_engine.logic.setup.first_run import is_first_run
1273
+
1274
+ if is_first_run():
1275
+ logger.info("First-run mode: Skipping adapter service registration")
1276
+ return
1277
+
1278
+ if not self.service_registry:
1279
+ logger.error("ServiceRegistry not initialized. Cannot register adapter services.")
1280
+ return
1281
+
1282
+ for adapter in self.adapters:
1283
+ try:
1284
+ # Generate authentication token for adapter - REQUIRED for security
1285
+ adapter_type = adapter.__class__.__name__.lower().replace("adapter", "")
1286
+ # Explicitly type as JSONDict for authentication service compatibility
1287
+ adapter_info: JSONDict = {
1288
+ "instance_id": str(id(adapter)),
1289
+ "startup_time": (
1290
+ self.time_service.now().isoformat()
1291
+ if self.time_service
1292
+ else datetime.now(timezone.utc).isoformat()
1293
+ ),
1294
+ }
1295
+
1296
+ # Get channel-specific info if available
1297
+ if hasattr(adapter, "get_channel_info"):
1298
+ adapter_info.update(adapter.get_channel_info())
1299
+
1300
+ # Get authentication service from service initializer
1301
+ auth_service = self.service_initializer.auth_service if self.service_initializer else None
1302
+
1303
+ # Create adapter token using the proper authentication service
1304
+ auth_token = (
1305
+ await auth_service._create_channel_token_for_adapter(adapter_type, adapter_info)
1306
+ if auth_service
1307
+ else None
1308
+ )
1309
+
1310
+ # Set token on adapter if it has the method
1311
+ if hasattr(adapter, "set_auth_token") and auth_token:
1312
+ adapter.set_auth_token(auth_token)
1313
+
1314
+ if auth_token:
1315
+ logger.info(f"Generated authentication token for {adapter_type} adapter")
1316
+
1317
+ registrations = adapter.get_services_to_register()
1318
+ for reg in registrations:
1319
+ if not isinstance(reg, AdapterServiceRegistration):
1320
+ logger.error(
1321
+ f"Adapter {adapter.__class__.__name__} provided an invalid AdapterServiceRegistration object: {reg}"
1322
+ )
1323
+ continue
1324
+
1325
+ # No need to check Service base class - adapters implement protocol interfaces
1326
+
1327
+ # All services are global now
1328
+ self.service_registry.register_service(
1329
+ service_type=reg.service_type, # Use the enum directly
1330
+ provider=reg.provider,
1331
+ priority=reg.priority,
1332
+ capabilities=reg.capabilities,
1333
+ )
1334
+ logger.info(f"Registered {reg.service_type.value} from {adapter.__class__.__name__}")
1335
+ except Exception as e:
1336
+ logger.error(f"Error registering services for adapter {adapter.__class__.__name__}: {e}", exc_info=True)
1337
+
1338
+ def _build_adapter_info(self, adapter: Any) -> JSONDict:
1339
+ """Build adapter info dictionary for authentication token creation."""
1340
+ adapter_info: JSONDict = {
1341
+ "instance_id": str(id(adapter)),
1342
+ "startup_time": (
1343
+ self.time_service.now().isoformat() if self.time_service else datetime.now(timezone.utc).isoformat()
1344
+ ),
1345
+ }
1346
+ # Get channel-specific info if available
1347
+ if hasattr(adapter, "get_channel_info"):
1348
+ adapter_info.update(adapter.get_channel_info())
1349
+ return adapter_info
1350
+
1351
+ async def _create_adapter_auth_token(
1352
+ self, adapter: Any, adapter_type: str, adapter_info: JSONDict
1353
+ ) -> Optional[str]:
1354
+ """Create and set authentication token for an adapter."""
1355
+ auth_service = self.service_initializer.auth_service if self.service_initializer else None
1356
+ if not auth_service:
1357
+ return None
1358
+
1359
+ auth_token = await auth_service._create_channel_token_for_adapter(adapter_type, adapter_info)
1360
+
1361
+ if hasattr(adapter, "set_auth_token") and auth_token:
1362
+ adapter.set_auth_token(auth_token)
1363
+
1364
+ if auth_token:
1365
+ logger.info(f"Generated authentication token for {adapter_type} adapter")
1366
+
1367
+ return auth_token
1368
+
1369
+ def _register_adapter_service(self, reg: AdapterServiceRegistration, adapter: Any) -> bool:
1370
+ """Register a single adapter service. Returns True if successful."""
1371
+ if not isinstance(reg, AdapterServiceRegistration):
1372
+ logger.error(
1373
+ f"Adapter {adapter.__class__.__name__} provided an invalid AdapterServiceRegistration object: {reg}"
1374
+ )
1375
+ return False
1376
+
1377
+ if self.service_registry is None:
1378
+ logger.error("Cannot register adapter service: service_registry is None")
1379
+ return False
1380
+
1381
+ self.service_registry.register_service(
1382
+ service_type=reg.service_type,
1383
+ provider=reg.provider,
1384
+ priority=reg.priority,
1385
+ capabilities=reg.capabilities,
1386
+ )
1387
+ logger.info(f"Registered {reg.service_type.value} from {adapter.__class__.__name__}")
1388
+ return True
1389
+
1390
+ async def _register_adapter_services_for_resume(self) -> None:
1391
+ """Register adapter services during resume_from_first_run.
1392
+
1393
+ This is identical to _register_adapter_services but without the is_first_run check,
1394
+ since we explicitly want to register during resume.
1395
+ """
1396
+ if not self.service_registry:
1397
+ logger.error("ServiceRegistry not initialized. Cannot register adapter services.")
1398
+ return
1399
+
1400
+ for adapter in self.adapters:
1401
+ try:
1402
+ adapter_type = adapter.__class__.__name__.lower().replace("adapter", "")
1403
+ adapter_info = self._build_adapter_info(adapter)
1404
+ await self._create_adapter_auth_token(adapter, adapter_type, adapter_info)
1405
+
1406
+ for reg in adapter.get_services_to_register():
1407
+ self._register_adapter_service(reg, adapter)
1408
+ except Exception as e:
1409
+ logger.error(f"Error registering services for adapter {adapter.__class__.__name__}: {e}", exc_info=True)
1410
+
1411
+ async def _build_components(self) -> None:
1412
+ """Build all processing components."""
1413
+ logger.info("[_build_components] Starting component building...")
1414
+ logger.info(f"[_build_components] llm_service: {self.llm_service}")
1415
+ logger.info(f"[_build_components] service_registry: {self.service_registry}")
1416
+ logger.info(f"[_build_components] service_initializer: {self.service_initializer}")
1417
+
1418
+ if self.service_initializer:
1419
+ logger.info(f"[_build_components] service_initializer.llm_service: {self.service_initializer.llm_service}")
1420
+ logger.info(
1421
+ f"[_build_components] service_initializer.service_registry: {self.service_initializer.service_registry}"
1422
+ )
1423
+
1424
+ # Check if LLM service is available - if not, check if this is first-run setup mode
1425
+ if not self.llm_service:
1426
+ from ciris_engine.logic.setup.first_run import is_first_run
1427
+
1428
+ if is_first_run():
1429
+ logger.info("[_build_components] First-run setup mode - LLM not yet configured")
1430
+ logger.info("[_build_components] Setup wizard will guide LLM configuration")
1431
+ else:
1432
+ logger.error("[_build_components] LLM service not available but setup was completed!")
1433
+ logger.error(
1434
+ "[_build_components] Check your LLM configuration - the agent cannot operate without an LLM"
1435
+ )
1436
+ return
1437
+
1438
+ try:
1439
+ self.component_builder = ComponentBuilder(self)
1440
+ logger.info("[_build_components] ComponentBuilder created successfully")
1441
+
1442
+ self.agent_processor = await self.component_builder.build_all_components()
1443
+ logger.info(f"[_build_components] agent_processor created: {self.agent_processor}")
1444
+
1445
+ # Set up thought tracking callback now that agent_processor exists
1446
+ # This avoids the race condition where RuntimeControlService tried to access
1447
+ # agent_processor during Phase 5 (SERVICES) before it was created in Phase 6 (COMPONENTS)
1448
+ if self.runtime_control_service:
1449
+ self.runtime_control_service.setup_thought_tracking() # type: ignore[attr-defined]
1450
+ logger.debug("Thought tracking callback set up after agent_processor creation")
1451
+
1452
+ except Exception as e:
1453
+ logger.error(f"[_build_components] Failed to build components: {e}", exc_info=True)
1454
+ raise
1455
+
1456
+ # Register core services after components are built
1457
+ self._register_core_services()
1458
+ logger.info("[_build_components] Component building completed")
1459
+
1460
+ async def _start_adapter_connections(self) -> None:
1461
+ """Start adapter connections and wait for them to be ready."""
1462
+ from ciris_engine.logic.setup.first_run import is_first_run
1463
+
1464
+ from .ciris_runtime_helpers import (
1465
+ create_adapter_lifecycle_tasks,
1466
+ log_adapter_configuration_details,
1467
+ verify_adapter_service_registration,
1468
+ wait_for_adapter_readiness,
1469
+ )
1470
+
1471
+ # Log adapter configuration details
1472
+ log_adapter_configuration_details(self.adapters)
1473
+
1474
+ # Check if this is first-run - skip agent processor if so
1475
+ first_run = is_first_run()
1476
+ if first_run:
1477
+ logger.info("")
1478
+ logger.info("=" * 70)
1479
+ logger.info("🔧 FIRST RUN DETECTED - Setup Wizard Mode")
1480
+ logger.info("=" * 70)
1481
+ logger.info("")
1482
+ logger.info("The agent processor will NOT start in first-run mode.")
1483
+ logger.info("Only the API server is running to provide the setup wizard.")
1484
+ logger.info("")
1485
+ logger.info("📋 Next Steps:")
1486
+ logger.info(" 1. Open your browser to: http://localhost:8080")
1487
+ logger.info(" 2. Complete the setup wizard")
1488
+ logger.info(" 3. Restart the agent with: ciris-agent")
1489
+ logger.info("")
1490
+ logger.info("After restart, the full agent will start normally.")
1491
+ logger.info("=" * 70)
1492
+ logger.info("")
1493
+
1494
+ # Only wait for adapters to be ready, but don't start agent processor
1495
+ adapters_ready = await wait_for_adapter_readiness(self.adapters)
1496
+ if not adapters_ready:
1497
+ raise RuntimeError("Adapters failed to become ready within timeout")
1498
+
1499
+ # No agent processor task in first-run mode
1500
+ self._adapter_tasks = create_adapter_lifecycle_tasks(self.adapters, agent_task=None)
1501
+
1502
+ # Skip service registration and processor - API will handle setup
1503
+ logger.info("✅ Setup wizard ready at http://localhost:8080")
1504
+ logger.info("Waiting for setup completion... (Press CTRL+C to exit)")
1505
+ return
1506
+
1507
+ # Normal mode - create agent processor task and adapter lifecycle tasks
1508
+ agent_task = asyncio.create_task(self._create_agent_processor_when_ready(), name="AgentProcessorTask")
1509
+ self._adapter_tasks = create_adapter_lifecycle_tasks(self.adapters, agent_task)
1510
+
1511
+ # Wait for adapters to be ready
1512
+ adapters_ready = await wait_for_adapter_readiness(self.adapters)
1513
+ if not adapters_ready:
1514
+ raise RuntimeError("Adapters failed to become ready within timeout")
1515
+
1516
+ # Register services and verify availability
1517
+ services_available = await verify_adapter_service_registration(self)
1518
+ if not services_available:
1519
+ raise RuntimeError("Failed to establish adapter connections within timeout")
1520
+
1521
+ # Final verification with the existing wait method
1522
+ await self._wait_for_critical_services(timeout=5.0)
1523
+
1524
+ def _is_using_ciris_proxy(self) -> bool:
1525
+ """Check if runtime is configured to use CIRIS proxy."""
1526
+ llm_base_url = os.getenv("OPENAI_API_BASE", "")
1527
+ return any(domain in llm_base_url for domain in CIRIS_PROXY_DOMAINS)
1528
+
1529
+ def _create_billing_token_handler(self, credit_provider: Any) -> Callable[..., Any]:
1530
+ """Create handler for billing token refresh signals."""
1531
+
1532
+ async def handle_billing_token_refreshed(signal: str, resource: str) -> None:
1533
+ new_token = os.getenv("CIRIS_BILLING_GOOGLE_ID_TOKEN", "")
1534
+ if new_token and credit_provider:
1535
+ credit_provider.update_google_id_token(new_token)
1536
+ logger.info("✓ Updated billing provider with refreshed Google ID token")
1537
+
1538
+ return handle_billing_token_refreshed
1539
+
1540
+ def _create_llm_token_handler(self) -> Callable[..., Any]:
1541
+ """Create handler for LLM service token refresh signals."""
1542
+
1543
+ async def handle_llm_token_refreshed(signal: str, resource: str) -> None:
1544
+ new_token = os.getenv("OPENAI_API_KEY", "")
1545
+ if not new_token:
1546
+ logger.warning("[LLM_TOKEN] No OPENAI_API_KEY in env after token refresh")
1547
+ return
1548
+
1549
+ self._update_llm_services_token(new_token)
1550
+
1551
+ return handle_llm_token_refreshed
1552
+
1553
+ def _update_llm_services_token(self, new_token: str) -> None:
1554
+ """Update all LLM services that use CIRIS proxy with new token."""
1555
+ if self.service_registry:
1556
+ llm_services = self.service_registry.get_services_by_type(ServiceType.LLM)
1557
+ for service in llm_services:
1558
+ self._update_service_token_if_ciris_proxy(service, new_token)
1559
+
1560
+ if self.llm_service:
1561
+ self._update_service_token_if_ciris_proxy(self.llm_service, new_token, is_primary=True)
1562
+
1563
+ def _update_service_token_if_ciris_proxy(self, service: Any, new_token: str, is_primary: bool = False) -> None:
1564
+ """Update a service's API key if it uses CIRIS proxy."""
1565
+ if not hasattr(service, "openai_config") or not service.openai_config:
1566
+ return
1567
+ if not hasattr(service, "update_api_key"):
1568
+ return
1569
+
1570
+ base_url = getattr(service.openai_config, "base_url", "") or ""
1571
+ if not any(domain in base_url for domain in CIRIS_PROXY_DOMAINS):
1572
+ return
1573
+
1574
+ service.update_api_key(new_token)
1575
+ label = "primary LLM service" if is_primary else type(service).__name__
1576
+ logger.info(f"✓ Updated {label} with refreshed token")
1577
+
1578
+ async def _reinitialize_billing_provider(self) -> None:
1579
+ """Reinitialize billing provider after setup completes.
1580
+
1581
+ Called during resume_from_first_run to set up billing now that
1582
+ environment variables (OPENAI_API_BASE, CIRIS_BILLING_GOOGLE_ID_TOKEN)
1583
+ are available from the newly created .env file.
1584
+ """
1585
+ resource_monitor = self._get_resource_monitor_for_billing()
1586
+ if not resource_monitor:
1587
+ return
1588
+
1589
+ is_android = "ANDROID_DATA" in os.environ
1590
+ using_ciris_proxy = self._is_using_ciris_proxy()
1591
+
1592
+ logger.info(f"Billing provider check: is_android={is_android}, using_ciris_proxy={using_ciris_proxy}")
1593
+ logger.info(f" OPENAI_API_BASE={os.getenv('OPENAI_API_BASE', '')}")
1594
+
1595
+ if not (is_android and using_ciris_proxy):
1596
+ logger.info("Billing provider not needed (not using CIRIS proxy or not Android)")
1597
+ return
1598
+
1599
+ google_id_token = os.getenv("CIRIS_BILLING_GOOGLE_ID_TOKEN", "")
1600
+ if not google_id_token:
1601
+ logger.warning("Android using CIRIS LLM proxy without Google ID token - billing provider not configured")
1602
+ return
1603
+
1604
+ credit_provider = self._create_billing_provider(google_id_token)
1605
+ resource_monitor.credit_provider = credit_provider
1606
+
1607
+ # Register token refresh handlers
1608
+ resource_monitor.signal_bus.register("token_refreshed", self._create_billing_token_handler(credit_provider))
1609
+ logger.info("✓ Reinitialized CIRISBillingProvider with JWT auth (CIRIS LLM proxy)")
1610
+ logger.info("✓ Registered token_refreshed handler for billing provider")
1611
+
1612
+ resource_monitor.signal_bus.register("token_refreshed", self._create_llm_token_handler())
1613
+ logger.info("✓ Registered token_refreshed handler for LLM service")
1614
+
1615
+ def _get_resource_monitor_for_billing(self) -> Any:
1616
+ """Get resource monitor service for billing initialization.
1617
+
1618
+ Returns the resource monitor service or None if not available.
1619
+ Uses Any type since we access implementation-specific attributes
1620
+ (credit_provider, signal_bus) not in the protocol.
1621
+ """
1622
+ if not self.service_initializer:
1623
+ logger.warning("Cannot reinitialize billing - service_initializer not available")
1624
+ return None
1625
+
1626
+ resource_monitor = self.service_initializer.resource_monitor_service
1627
+ if not resource_monitor:
1628
+ logger.warning("Cannot reinitialize billing - resource_monitor_service not available")
1629
+ return None
1630
+
1631
+ return resource_monitor
1632
+
1633
+ def _create_billing_provider(self, google_id_token: str) -> Any:
1634
+ """Create and configure the CIRIS billing provider."""
1635
+ from ciris_engine.logic.services.infrastructure.resource_monitor import CIRISBillingProvider
1636
+
1637
+ base_url = get_billing_url() # Checks env var first, then falls back to central config
1638
+ timeout = float(os.getenv("CIRIS_BILLING_TIMEOUT_SECONDS", "5.0"))
1639
+ cache_ttl = int(os.getenv("CIRIS_BILLING_CACHE_TTL_SECONDS", "15"))
1640
+ fail_open = os.getenv("CIRIS_BILLING_FAIL_OPEN", "false").lower() == "true"
1641
+
1642
+ def get_fresh_token() -> str:
1643
+ return os.getenv("CIRIS_BILLING_GOOGLE_ID_TOKEN", "")
1644
+
1645
+ return CIRISBillingProvider(
1646
+ google_id_token=google_id_token,
1647
+ token_refresh_callback=get_fresh_token,
1648
+ base_url=base_url,
1649
+ timeout_seconds=timeout,
1650
+ cache_ttl_seconds=cache_ttl,
1651
+ fail_open=fail_open,
1652
+ )
1653
+
1654
+ def _resume_reload_environment(
1655
+ self, log_step: Callable[[int, int, str], None], total_steps: int
1656
+ ) -> "EssentialConfig":
1657
+ """Reload environment and config during resume from first-run."""
1658
+ from dotenv import load_dotenv
1659
+
1660
+ from ciris_engine.logic.setup.first_run import get_default_config_path
1661
+
1662
+ config_path = get_default_config_path()
1663
+ log_step(2, total_steps, f"Config path: {config_path}, exists: {config_path.exists()}")
1664
+ if config_path.exists():
1665
+ load_dotenv(config_path, override=True)
1666
+ log_step(2, total_steps, f"✓ Reloaded environment from {config_path}")
1667
+ else:
1668
+ log_step(2, total_steps, f"⚠️ Config path does not exist: {config_path}")
1669
+
1670
+ config = self._ensure_config()
1671
+ config.load_env_vars()
1672
+ log_step(3, total_steps, f"✓ Config reloaded - default_template: {config.default_template}")
1673
+ return config
1674
+
1675
+ async def _resume_initialize_identity(
1676
+ self, config: "EssentialConfig", log_step: Callable[[int, int, str], None], total_steps: int
1677
+ ) -> None:
1678
+ """Initialize identity with user-selected template during resume."""
1679
+ log_step(
1680
+ 4,
1681
+ total_steps,
1682
+ f"Initializing identity... identity_manager={self.identity_manager is not None}, "
1683
+ f"time_service={self.time_service is not None}",
1684
+ )
1685
+ if self.identity_manager and self.time_service:
1686
+ self.identity_manager = IdentityManager(config, self.time_service)
1687
+ self.agent_identity = await self.identity_manager.initialize_identity()
1688
+ await self._create_startup_node()
1689
+ log_step(
1690
+ 4,
1691
+ total_steps,
1692
+ f"✓ Agent identity initialized: {self.agent_identity.agent_id if self.agent_identity else 'None'}",
1693
+ )
1694
+ else:
1695
+ log_step(4, total_steps, "⚠️ Skipped identity init - missing identity_manager or time_service")
1696
+
1697
+ async def _resume_migrate_cognitive_behaviors(
1698
+ self, log_step: Callable[[int, int, str], None], total_steps: int
1699
+ ) -> None:
1700
+ """Migrate cognitive state behaviors from template during resume."""
1701
+ log_step(5, total_steps, "Migrating cognitive state behaviors from template...")
1702
+ if self.identity_manager and self.identity_manager.agent_template:
1703
+ template_name = getattr(self.identity_manager.agent_template, "name", "UNKNOWN")
1704
+ cognitive_behaviors = getattr(self.identity_manager.agent_template, "cognitive_state_behaviors", None)
1705
+ if cognitive_behaviors:
1706
+ log_step(
1707
+ 5,
1708
+ total_steps,
1709
+ f"Template '{template_name}' has cognitive_state_behaviors: "
1710
+ f"wakeup.enabled={cognitive_behaviors.wakeup.enabled}",
1711
+ )
1712
+ else:
1713
+ log_step(
1714
+ 5, total_steps, f"Template '{template_name}' has no cognitive_state_behaviors (will use defaults)"
1715
+ )
1716
+ await self._migrate_cognitive_state_behaviors_to_graph(force_from_template=True)
1717
+ log_step(5, total_steps, "✓ Cognitive state behaviors migrated from template")
1718
+ else:
1719
+ log_step(5, total_steps, "⚠️ No template available - using default cognitive behaviors")
1720
+ await self._migrate_cognitive_state_behaviors_to_graph(force_from_template=False)
1721
+
1722
+ def _set_service_runtime_references(self) -> None:
1723
+ """Set runtime references on services that need them."""
1724
+ if self.audit_service:
1725
+ self.audit_service._runtime = self # type: ignore[attr-defined]
1726
+ logger.debug("Set runtime reference on audit service for trace correlations")
1727
+
1728
+ if self.visibility_service:
1729
+ self.visibility_service._runtime = self # type: ignore[attr-defined]
1730
+ logger.debug("Set runtime reference on visibility service for trace retrieval")
1731
+
1732
+ if self.runtime_control_service:
1733
+ if hasattr(self.runtime_control_service, "_set_runtime"):
1734
+ self.runtime_control_service._set_runtime(self)
1735
+ else:
1736
+ self.runtime_control_service.runtime = self # type: ignore[attr-defined]
1737
+ logger.info("Updated runtime control service with runtime reference")
1738
+
1739
+ if self.telemetry_service and hasattr(self.telemetry_service, "_set_runtime"):
1740
+ self.telemetry_service._set_runtime(self)
1741
+ logger.info("Updated telemetry service with runtime reference for aggregator")
1742
+
1743
+ async def _resume_initialize_core_services(
1744
+ self, config: "EssentialConfig", log_step: Callable[[int, int, str], None], total_steps: int
1745
+ ) -> None:
1746
+ """Initialize core services during resume."""
1747
+ log_step(
1748
+ 6,
1749
+ total_steps,
1750
+ f"Initializing core services... service_initializer={self.service_initializer is not None}, "
1751
+ f"agent_identity={self.agent_identity is not None}",
1752
+ )
1753
+ if not (self.service_initializer and self.agent_identity):
1754
+ log_step(6, total_steps, "⚠️ Skipped core services - missing service_initializer or agent_identity")
1755
+ return
1756
+
1757
+ await self.service_initializer.initialize_all_services(
1758
+ config,
1759
+ self.essential_config,
1760
+ self.agent_identity.agent_id,
1761
+ self.startup_channel_id,
1762
+ self.modules_to_load,
1763
+ )
1764
+ log_step(6, total_steps, "✓ Core services initialized")
1765
+
1766
+ self._set_service_runtime_references()
1767
+
1768
+ if self.modules_to_load:
1769
+ log_step(6, total_steps, f"Loading {len(self.modules_to_load)} external modules: {self.modules_to_load}")
1770
+ await self.service_initializer.load_modules(self.modules_to_load)
1771
+
1772
+ async def _resume_initialize_llm(self, log_step: Callable[[int, int, str], None], total_steps: int) -> None:
1773
+ """Initialize LLM service during resume."""
1774
+ log_step(
1775
+ 10, total_steps, f"Initializing LLM service... service_initializer={self.service_initializer is not None}"
1776
+ )
1777
+ if self.service_initializer:
1778
+ config = self._ensure_config()
1779
+ await self.service_initializer._initialize_llm_services(config, self.modules_to_load)
1780
+ log_step(10, total_steps, "✓ LLM service initialized")
1781
+ else:
1782
+ log_step(10, total_steps, "⚠️ Skipped LLM init - no service_initializer")
1783
+
1784
+ def _resume_reinject_adapters(self, log_step: Callable[[int, int, str], None], total_steps: int) -> None:
1785
+ """Re-inject services into running adapters during resume."""
1786
+ log_step(11, total_steps, f"Re-injecting services into {len(self.adapters)} adapters...")
1787
+ for adapter in self.adapters:
1788
+ if hasattr(adapter, "reinject_services"):
1789
+ adapter.reinject_services()
1790
+ log_step(11, total_steps, f"✓ Re-injected services into {adapter.__class__.__name__}")
1791
+
1792
+ async def _resume_auto_enable_android_adapters(self) -> None:
1793
+ """Auto-enable Android-specific adapters after resume.
1794
+
1795
+ Calls _auto_enable_android_adapters on any adapters that have it,
1796
+ which enables ciris_hosted_tools (web_search) when:
1797
+ - Running on Android with Google auth
1798
+ - The adapter is not already loaded
1799
+ """
1800
+ for adapter in self.adapters:
1801
+ if hasattr(adapter, "_auto_enable_android_adapters"):
1802
+ try:
1803
+ await adapter._auto_enable_android_adapters()
1804
+ logger.info(f"[RESUME] Called _auto_enable_android_adapters on {adapter.__class__.__name__}")
1805
+ except Exception as e:
1806
+ logger.warning(
1807
+ f"[RESUME] Failed to auto-enable Android adapters on {adapter.__class__.__name__}: {e}"
1808
+ )
1809
+
1810
+ async def resume_from_first_run(self) -> None:
1811
+ """Resume initialization after setup wizard completes.
1812
+
1813
+ This continues from the point where first-run mode paused (line 1088).
1814
+ It executes the same steps as normal mode initialization.
1815
+ """
1816
+ # Set flag AND timestamp to prevent premature shutdown during resume
1817
+ # The timestamp allows timeout detection for stuck resume scenarios
1818
+ self._resume_in_progress = True
1819
+ self._resume_started_at = time.time()
1820
+ logger.info(f"[RESUME] Started at {self._resume_started_at:.3f}, _resume_in_progress=True")
1821
+
1822
+ start_time = time.time()
1823
+ total_steps = 14
1824
+
1825
+ def log_step(step_num: int, total: int, msg: str) -> None:
1826
+ elapsed = time.time() - start_time
1827
+ logger.warning(f"[RESUME {step_num}/{total}] [{elapsed:.2f}s] {msg}")
1828
+
1829
+ logger.warning("")
1830
+ logger.warning("=" * 70)
1831
+ logger.warning("🔄 RESUMING FROM FIRST-RUN MODE")
1832
+ logger.warning("=" * 70)
1833
+ logger.warning("")
1834
+ log_step(1, total_steps, "Starting resume from first-run...")
1835
+
1836
+ # Steps 2-3: Reload environment and config
1837
+ config = self._resume_reload_environment(log_step, total_steps)
1838
+
1839
+ # Step 4: Initialize identity with user-selected template
1840
+ await self._resume_initialize_identity(config, log_step, total_steps)
1841
+
1842
+ # Step 5: Migrate cognitive behaviors from template
1843
+ await self._resume_migrate_cognitive_behaviors(log_step, total_steps)
1844
+
1845
+ # Step 6: Initialize core services
1846
+ await self._resume_initialize_core_services(config, log_step, total_steps)
1847
+
1848
+ # Step 7: Register adapter services
1849
+ log_step(7, total_steps, "Registering adapter services...")
1850
+ await self._register_adapter_services_for_resume()
1851
+ log_step(7, total_steps, "✓ Adapter services registered")
1852
+
1853
+ # Step 8: Initialize maintenance service
1854
+ log_step(
1855
+ 8, total_steps, f"Initializing maintenance... maintenance_service={self.maintenance_service is not None}"
1856
+ )
1857
+ if self.maintenance_service:
1858
+ await self._perform_startup_maintenance()
1859
+ log_step(8, total_steps, "✓ Maintenance service initialized")
1860
+ else:
1861
+ log_step(8, total_steps, "⚠️ Skipped maintenance - no maintenance_service")
1862
+
1863
+ # Step 9: Reinitialize billing provider
1864
+ log_step(9, total_steps, "Reinitializing billing provider...")
1865
+ await self._reinitialize_billing_provider()
1866
+ log_step(9, total_steps, "✓ Billing provider reinitialized")
1867
+
1868
+ # Step 10: Initialize LLM service
1869
+ await self._resume_initialize_llm(log_step, total_steps)
1870
+
1871
+ # Step 11: Re-inject services into adapters
1872
+ self._resume_reinject_adapters(log_step, total_steps)
1873
+
1874
+ # Step 12: Auto-enable Android-specific adapters (ciris_hosted_tools with web_search)
1875
+ log_step(12, total_steps, "Auto-enabling Android adapters...")
1876
+ await self._resume_auto_enable_android_adapters()
1877
+ log_step(12, total_steps, "✓ Android adapters auto-enabled")
1878
+
1879
+ # Step 13: Build cognitive components
1880
+ log_step(13, total_steps, "Building cognitive components...")
1881
+ await self._build_components()
1882
+ log_step(13, total_steps, "✓ Cognitive components built")
1883
+
1884
+ # Step 14: Create agent processor task
1885
+ log_step(14, total_steps, "Creating agent processor task...")
1886
+ self._agent_task = asyncio.create_task(self._create_agent_processor_when_ready(), name="AgentProcessorTask")
1887
+ log_step(14, total_steps, "Waiting for critical services (timeout=10s)...")
1888
+ await self._wait_for_critical_services(timeout=10.0)
1889
+
1890
+ elapsed = time.time() - start_time
1891
+ logger.warning("")
1892
+ logger.warning(f"✅ RESUME COMPLETE in {elapsed:.2f}s - Agent processor started!")
1893
+ logger.warning("=" * 70)
1894
+ logger.warning("")
1895
+
1896
+ # Clear the resume flag and timestamp - safe to shutdown now
1897
+ self._resume_in_progress = False
1898
+ self._resume_started_at = None
1899
+ logger.info(f"[RESUME] Completed in {elapsed:.2f}s, _resume_in_progress=False")
1900
+
1901
+ async def _create_agent_processor_when_ready(self) -> None:
1902
+ """Create and start agent processor once all services are ready.
1903
+
1904
+ This replaces the placeholder task pattern with proper dependency injection.
1905
+ """
1906
+ logger.info("Waiting for services to be ready before starting agent processor...")
1907
+
1908
+ # Wait for all critical services to be available
1909
+ await self._wait_for_critical_services(timeout=30.0)
1910
+
1911
+ # Check if agent processor is built (may be None in first-run setup mode)
1912
+ if not self.agent_processor:
1913
+ from ciris_engine.logic.setup.first_run import is_first_run
1914
+
1915
+ if is_first_run():
1916
+ logger.info("Agent processor not started - first-run setup mode active")
1917
+ else:
1918
+ logger.error("Agent processor not initialized but setup was completed!")
1919
+ logger.error("This indicates a configuration error - check LLM settings")
1920
+ return
1921
+
1922
+ # Start the multi-service sink if available
1923
+ if self.bus_manager:
1924
+ _sink_task = asyncio.create_task(self.bus_manager.start())
1925
+ logger.info("Started multi-service sink as background task")
1926
+
1927
+ # Start agent processing with default rounds
1928
+ effective_num_rounds = DEFAULT_NUM_ROUNDS
1929
+ logger.info(
1930
+ f"Starting agent processor (num_rounds={effective_num_rounds if effective_num_rounds != -1 else 'infinite'})..."
1931
+ )
1932
+
1933
+ # Start the actual agent processing
1934
+ await self.agent_processor.start_processing(effective_num_rounds)
1935
+
1936
+ def _register_core_services(self) -> None:
1937
+ """Register core services in the service registry."""
1938
+ self.service_initializer.register_core_services()
1939
+
1940
+ def _build_action_dispatcher(self, dependencies: Any) -> ActionDispatcher:
1941
+ """Build action dispatcher. Override in subclasses for custom sinks."""
1942
+ config = self._ensure_config()
1943
+ # Create BusManager for action handlers
1944
+ from ciris_engine.logic.buses import BusManager
1945
+
1946
+ if not self.service_registry:
1947
+ raise RuntimeError("Service registry not initialized")
1948
+ logger.debug(f"[AUDIT self.service_initializer exists: {self.service_initializer is not None}")
1949
+ if self.service_initializer:
1950
+ logger.debug(f"[AUDIT service_initializer.audit_service: {self.service_initializer.audit_service}")
1951
+ logger.debug(f"[AUDIT Creating BusManager with audit_service={self.audit_service}")
1952
+ logger.debug(f"[AUDIT self.audit_service type: {type(self.audit_service)}")
1953
+ logger.debug(f"[AUDIT self.audit_service is None: {self.audit_service is None}")
1954
+
1955
+ assert self.service_registry is not None
1956
+ # BusManager requires TimeServiceProtocol, not Optional[TimeService]
1957
+ if self.time_service is None:
1958
+ raise RuntimeError("TimeService must be initialized before creating BusManager")
1959
+
1960
+ bus_manager = BusManager(
1961
+ self.service_registry,
1962
+ time_service=self.time_service,
1963
+ telemetry_service=self.telemetry_service,
1964
+ audit_service=self.audit_service,
1965
+ )
1966
+
1967
+ return build_action_dispatcher(
1968
+ bus_manager=bus_manager,
1969
+ time_service=self.time_service,
1970
+ shutdown_callback=dependencies.shutdown_callback,
1971
+ max_rounds=config.workflow.max_rounds,
1972
+ telemetry_service=self.telemetry_service,
1973
+ secrets_service=self.secrets_service,
1974
+ )
1975
+
1976
+ def _should_exit_runtime_loop(
1977
+ self, agent_task: Optional[asyncio.Task[Any]], shutdown_logged: bool
1978
+ ) -> tuple[bool, bool]:
1979
+ """Check if runtime loop should exit.
1980
+
1981
+ Returns:
1982
+ Tuple of (should_exit, shutdown_logged)
1983
+ """
1984
+ if agent_task and agent_task.done():
1985
+ return True, shutdown_logged
1986
+ if (self._shutdown_event and self._shutdown_event.is_set()) or is_global_shutdown_requested():
1987
+ return True, True
1988
+ return False, shutdown_logged
1989
+
1990
+ def _handle_completed_runtime_tasks(
1991
+ self,
1992
+ done: set[asyncio.Task[Any]],
1993
+ agent_task: Optional[asyncio.Task[Any]],
1994
+ adapter_tasks: List[asyncio.Task[Any]],
1995
+ all_tasks: list[asyncio.Task[Any]],
1996
+ ) -> tuple[bool, bool]:
1997
+ """Handle completed runtime tasks.
1998
+
1999
+ Returns:
2000
+ Tuple of (should_break, is_shutdown)
2001
+ """
2002
+ from .ciris_runtime_helpers import handle_runtime_agent_task_completion, handle_runtime_task_failures
2003
+
2004
+ # Check for shutdown signal
2005
+ if (self._shutdown_event and self._shutdown_event.is_set()) or is_global_shutdown_requested():
2006
+ return True, True
2007
+
2008
+ # Check if agent task completed
2009
+ if agent_task and agent_task in done:
2010
+ handle_runtime_agent_task_completion(self, agent_task, adapter_tasks)
2011
+ return True, False
2012
+
2013
+ # Handle other task failures
2014
+ excluded_tasks = {t for t in all_tasks if t.get_name() in ["ShutdownEventWait", "GlobalShutdownWait"]}
2015
+ handle_runtime_task_failures(self, done, excluded_tasks)
2016
+ return False, False
2017
+
2018
+ async def run(self, _: Optional[int] = None) -> None:
2019
+ """Run the agent processing loop with shutdown monitoring."""
2020
+ from .ciris_runtime_helpers import (
2021
+ finalize_runtime_execution,
2022
+ monitor_runtime_shutdown_signals,
2023
+ setup_runtime_monitoring_tasks,
2024
+ )
2025
+
2026
+ if not self._initialized:
2027
+ await self.initialize()
2028
+
2029
+ try:
2030
+ # Set up runtime monitoring tasks
2031
+ agent_task, adapter_tasks, all_tasks = setup_runtime_monitoring_tasks(self)
2032
+ if not all_tasks:
2033
+ logger.error("No tasks to monitor - exiting")
2034
+ return
2035
+
2036
+ # Keep monitoring until shutdown or agent task completes
2037
+ shutdown_logged = False
2038
+ while True:
2039
+ # Check exit conditions
2040
+ should_exit, shutdown_logged = self._should_exit_runtime_loop(agent_task, shutdown_logged)
2041
+ if should_exit:
2042
+ break
2043
+
2044
+ done, pending = await asyncio.wait(all_tasks, return_when=asyncio.FIRST_COMPLETED, timeout=1.0)
2045
+
2046
+ # Remove completed tasks from all_tasks to avoid re-processing
2047
+ all_tasks = [t for t in all_tasks if t not in done]
2048
+
2049
+ # Monitor shutdown signals
2050
+ shutdown_logged = monitor_runtime_shutdown_signals(self, shutdown_logged)
2051
+
2052
+ # Handle task completion
2053
+ should_break, _ = self._handle_completed_runtime_tasks(done, agent_task, adapter_tasks, all_tasks)
2054
+ if should_break:
2055
+ break
2056
+
2057
+ # Finalize execution
2058
+ await finalize_runtime_execution(self, set(pending) if "pending" in locals() else set())
2059
+
2060
+ except KeyboardInterrupt:
2061
+ logger.info("Received interrupt signal. Requesting shutdown.")
2062
+ self.request_shutdown("KeyboardInterrupt")
2063
+ except Exception as e:
2064
+ logger.error(f"Runtime error: {e}", exc_info=True)
2065
+ finally:
2066
+ logger.debug("Runtime.run() entering finally block")
2067
+ await self.shutdown()
2068
+ logger.debug("Runtime.run() exiting finally block")
2069
+
2070
+ async def shutdown(self) -> None:
2071
+ """Gracefully shutdown all services with continuity awareness."""
2072
+ from .ciris_runtime_helpers import (
2073
+ cleanup_runtime_resources,
2074
+ execute_final_maintenance_tasks,
2075
+ execute_service_shutdown_sequence,
2076
+ finalize_shutdown_logging,
2077
+ handle_adapter_shutdown_cleanup,
2078
+ handle_agent_processor_shutdown,
2079
+ prepare_shutdown_maintenance_tasks,
2080
+ preserve_critical_system_state,
2081
+ validate_shutdown_completion,
2082
+ validate_shutdown_preconditions,
2083
+ )
2084
+
2085
+ # 1. Validate preconditions and early exit if needed
2086
+ if not validate_shutdown_preconditions(self):
2087
+ return
2088
+
2089
+ logger.info("Shutting down CIRIS Runtime...")
2090
+
2091
+ # 2. Prepare maintenance and stop scheduled services
2092
+ await prepare_shutdown_maintenance_tasks(self)
2093
+
2094
+ # 3. Execute final maintenance tasks
2095
+ await execute_final_maintenance_tasks(self)
2096
+
2097
+ # 4. Preserve critical system state
2098
+ await preserve_critical_system_state(self)
2099
+
2100
+ # 5. Handle agent processor shutdown
2101
+ logger.info("Initiating shutdown sequence for CIRIS Runtime...")
2102
+ self._ensure_shutdown_event()
2103
+ if self._shutdown_event:
2104
+ self._shutdown_event.set()
2105
+
2106
+ await handle_agent_processor_shutdown(self)
2107
+
2108
+ # 6. Handle adapter cleanup
2109
+ await handle_adapter_shutdown_cleanup(self)
2110
+
2111
+ # 7. Execute service shutdown sequence
2112
+ logger.debug("Stopping core services...")
2113
+ await execute_service_shutdown_sequence(self)
2114
+
2115
+ # 8. Finalize logging and cleanup resources
2116
+ await finalize_shutdown_logging(self)
2117
+ await cleanup_runtime_resources(self)
2118
+ validate_shutdown_completion(self)
2119
+ logger.debug("Shutdown method returning")
2120
+
2121
+ async def _create_startup_node(self) -> None:
2122
+ """Create startup node for continuity tracking."""
2123
+ try:
2124
+ from ciris_engine.schemas.services.graph_core import GraphNode, GraphScope, NodeType
2125
+ from ciris_engine.schemas.types import JSONDict
2126
+
2127
+ # Create memory node for startup
2128
+ startup_node = GraphNode(
2129
+ id=f"startup_{self.time_service.now().isoformat() if self.time_service else datetime.now(timezone.utc).isoformat()}",
2130
+ type=NodeType.AGENT,
2131
+ scope=GraphScope.IDENTITY,
2132
+ attributes={"created_by": "runtime_startup", "tags": ["startup", "continuity_awareness"]},
2133
+ )
2134
+
2135
+ # Store in memory service
2136
+ if self.memory_service:
2137
+ await self.memory_service.memorize(startup_node)
2138
+ logger.info(f"Created startup continuity node: {startup_node.id}")
2139
+
2140
+ except Exception as e:
2141
+ logger.error(f"Failed to create startup node: {e}")
2142
+
2143
+ def _determine_shutdown_consent_status(self) -> str:
2144
+ """Determine if shutdown was consensual based on agent processor result.
2145
+
2146
+ Returns:
2147
+ Consent status: 'accepted', 'rejected', or 'manual'
2148
+ """
2149
+ if not self.agent_processor or not hasattr(self.agent_processor, "shutdown_processor"):
2150
+ return "manual"
2151
+
2152
+ shutdown_proc = self.agent_processor.shutdown_processor
2153
+ if not shutdown_proc or not hasattr(shutdown_proc, "shutdown_result"):
2154
+ return "manual"
2155
+
2156
+ result = shutdown_proc.shutdown_result
2157
+ if not result:
2158
+ return "manual"
2159
+
2160
+ if result.action == "shutdown_accepted" or result.status == "completed":
2161
+ return "accepted"
2162
+ elif result.action == "shutdown_rejected" or result.status == "rejected":
2163
+ return "rejected"
2164
+
2165
+ return "manual"
2166
+
2167
+ def _build_shutdown_node_attributes(self, reason: str, consent_status: str) -> JSONDict:
2168
+ """Build attributes dict for shutdown memory node.
2169
+
2170
+ Args:
2171
+ reason: Shutdown reason text
2172
+ consent_status: Consent status ('accepted', 'rejected', 'manual')
2173
+
2174
+ Returns:
2175
+ Dictionary of node attributes
2176
+ """
2177
+ now = self.time_service.now() if self.time_service else datetime.now(timezone.utc)
2178
+ return {
2179
+ "created_at": now.isoformat(),
2180
+ "updated_at": now.isoformat(),
2181
+ "created_by": "runtime_shutdown",
2182
+ "tags": ["shutdown", "continuity_awareness"],
2183
+ "reason": reason,
2184
+ "consent_status": consent_status,
2185
+ }
2186
+
2187
+ async def _update_identity_with_shutdown_reference(self, shutdown_node_id: str) -> None:
2188
+ """Update agent identity with shutdown memory reference.
2189
+
2190
+ Args:
2191
+ shutdown_node_id: ID of the shutdown node created
2192
+ """
2193
+ if not self.agent_identity or not hasattr(self.agent_identity, "core_profile"):
2194
+ return
2195
+
2196
+ self.agent_identity.core_profile.last_shutdown_memory = shutdown_node_id
2197
+
2198
+ # Increment modification count
2199
+ if hasattr(self.agent_identity, "identity_metadata"):
2200
+ self.agent_identity.identity_metadata.modification_count += 1
2201
+
2202
+ # Save updated identity
2203
+ if self.identity_manager:
2204
+ await self.identity_manager._save_identity_to_graph(self.agent_identity)
2205
+ logger.debug("Agent identity updates saved to persistence layer")
2206
+ else:
2207
+ logger.debug("Agent identity updates stored in memory graph")
2208
+
2209
+ async def _preserve_shutdown_continuity(self) -> None:
2210
+ """Preserve agent state for future reactivation."""
2211
+ try:
2212
+ from ciris_engine.schemas.runtime.extended import ShutdownContext
2213
+ from ciris_engine.schemas.services.graph_core import GraphNode, GraphScope, NodeType
2214
+
2215
+ # Create shutdown context
2216
+ shutdown_context = ShutdownContext(
2217
+ is_terminal=False,
2218
+ reason=self._shutdown_reason or "Graceful shutdown",
2219
+ initiated_by="runtime",
2220
+ allow_deferral=False,
2221
+ expected_reactivation=None,
2222
+ agreement_context=None,
2223
+ )
2224
+
2225
+ # Determine consent status and build node
2226
+ consent_status = self._determine_shutdown_consent_status()
2227
+ now = self.time_service.now() if self.time_service else datetime.now(timezone.utc)
2228
+
2229
+ shutdown_node = GraphNode(
2230
+ id=f"shutdown_{now.isoformat()}",
2231
+ type=NodeType.AGENT,
2232
+ scope=GraphScope.IDENTITY,
2233
+ attributes=self._build_shutdown_node_attributes(shutdown_context.reason, consent_status),
2234
+ )
2235
+
2236
+ # Store in memory service
2237
+ if self.memory_service:
2238
+ await self.memory_service.memorize(shutdown_node)
2239
+ logger.info(f"Preserved shutdown continuity: {shutdown_node.id}")
2240
+ await self._update_identity_with_shutdown_reference(shutdown_node.id)
2241
+
2242
+ except Exception as e:
2243
+ logger.error(f"Failed to preserve shutdown continuity: {e}")
2244
+
2245
+ def _parse_bootstrap_config(
2246
+ self,
2247
+ bootstrap: Optional["RuntimeBootstrapConfig"],
2248
+ essential_config: Optional[EssentialConfig],
2249
+ startup_channel_id: Optional[str],
2250
+ adapter_types: List[str],
2251
+ adapter_configs: Optional[Dict[str, AdapterConfig]],
2252
+ kwargs: JSONDict,
2253
+ ) -> None:
2254
+ """Parse bootstrap configuration or create from legacy parameters."""
2255
+ if bootstrap is not None:
2256
+ self.bootstrap = bootstrap
2257
+ self.essential_config = essential_config or EssentialConfig()
2258
+ self.essential_config.load_env_vars() # Load environment variables
2259
+ self.startup_channel_id = bootstrap.startup_channel_id or ""
2260
+ self.adapter_configs = bootstrap.adapter_overrides
2261
+ self.modules_to_load = bootstrap.modules
2262
+ self.debug = bootstrap.debug
2263
+ self._preload_tasks = bootstrap.preload_tasks
2264
+ else:
2265
+ self._create_bootstrap_from_legacy(
2266
+ essential_config, startup_channel_id, adapter_types, adapter_configs, kwargs
2267
+ )
2268
+
2269
+ def _create_bootstrap_from_legacy(
2270
+ self,
2271
+ essential_config: Optional[EssentialConfig],
2272
+ startup_channel_id: Optional[str],
2273
+ adapter_types: List[str],
2274
+ adapter_configs: Optional[Dict[str, AdapterConfig]],
2275
+ kwargs: JSONDict,
2276
+ ) -> None:
2277
+ """Create bootstrap config from legacy parameters."""
2278
+ self.essential_config = essential_config or EssentialConfig()
2279
+ self.essential_config.load_env_vars() # Load environment variables
2280
+ self.startup_channel_id = startup_channel_id or ""
2281
+ self.adapter_configs = adapter_configs or {}
2282
+ # Type narrow: kwargs.get returns JSONDict value, narrow to expected types
2283
+ modules_raw = kwargs.get("modules", [])
2284
+ self.modules_to_load = modules_raw if isinstance(modules_raw, list) else []
2285
+ debug_raw = kwargs.get("debug", False)
2286
+ self.debug = debug_raw if isinstance(debug_raw, bool) else False
2287
+ self._preload_tasks = []
2288
+
2289
+ from ciris_engine.schemas.runtime.adapter_management import AdapterLoadRequest
2290
+ from ciris_engine.schemas.runtime.bootstrap import RuntimeBootstrapConfig
2291
+
2292
+ adapter_load_requests = [
2293
+ AdapterLoadRequest(adapter_type=atype, adapter_id=atype, auto_start=True) for atype in adapter_types
2294
+ ]
2295
+ self.bootstrap = RuntimeBootstrapConfig(
2296
+ adapters=adapter_load_requests,
2297
+ adapter_overrides=self.adapter_configs,
2298
+ modules=self.modules_to_load,
2299
+ startup_channel_id=self.startup_channel_id,
2300
+ debug=self.debug,
2301
+ preload_tasks=self._preload_tasks,
2302
+ )
2303
+
2304
+ def _check_mock_llm(self) -> None:
2305
+ """Check for mock LLM environment variable and add to modules if needed."""
2306
+ if os.environ.get("CIRIS_MOCK_LLM", "").lower() in ("true", "1", "yes", "on"):
2307
+ logger.warning("CIRIS_MOCK_LLM environment variable detected in CIRISRuntime")
2308
+ if "mock_llm" not in self.modules_to_load:
2309
+ self.modules_to_load.append("mock_llm")
2310
+ logger.info("Added mock_llm to modules to load")
2311
+
2312
+ def _load_adapters_from_bootstrap(self) -> None:
2313
+ """Load adapters from bootstrap configuration."""
2314
+ for load_request in self.bootstrap.adapters:
2315
+ try:
2316
+ adapter_class = load_adapter(load_request.adapter_type)
2317
+
2318
+ # Create AdapterStartupContext
2319
+ from ciris_engine.schemas.adapters.runtime_context import AdapterStartupContext
2320
+
2321
+ context = AdapterStartupContext(
2322
+ essential_config=self.essential_config or EssentialConfig(),
2323
+ modules_to_load=self.modules_to_load,
2324
+ startup_channel_id=self.startup_channel_id or "",
2325
+ debug=self.debug,
2326
+ bus_manager=None, # Will be set after initialization
2327
+ time_service=None, # Will be set after initialization
2328
+ service_registry=None, # Will be set after initialization
2329
+ )
2330
+
2331
+ # Apply overrides if present
2332
+ config = load_request.config or AdapterConfig(adapter_type=load_request.adapter_type)
2333
+ if load_request.adapter_id in self.adapter_configs:
2334
+ config = self.adapter_configs[load_request.adapter_id]
2335
+
2336
+ # Create adapter with context
2337
+ # Pass the settings as adapter_config so adapters can find them
2338
+ adapter_instance = adapter_class(self, context=context, adapter_config=config.settings) # type: ignore[call-arg]
2339
+ self.adapters.append(adapter_instance)
2340
+ logger.info(f"Successfully loaded adapter: {load_request.adapter_id}")
2341
+ except Exception as e:
2342
+ logger.error(f"Failed to load adapter '{load_request.adapter_id}': {e}", exc_info=True)