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,1337 @@
1
+ """
2
+ Helper functions for telemetry service refactoring.
3
+
4
+ These break down the complex get_telemetry_summary method into focused,
5
+ testable components. All functions fail fast and loud - no fallback data.
6
+ """
7
+
8
+ import logging
9
+ from datetime import datetime, timedelta, timezone
10
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, TypeVar, Union
11
+
12
+ from ciris_engine.schemas.types import JSONDict
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ from ciris_engine.logic.services.graph.telemetry_service.exceptions import (
17
+ MemoryBusUnavailableError,
18
+ MetricCollectionError,
19
+ NoThoughtDataError,
20
+ QueueStatusUnavailableError,
21
+ RuntimeControlBusUnavailableError,
22
+ ServiceStartTimeUnavailableError,
23
+ ThoughtDepthQueryError,
24
+ UnknownMetricTypeError,
25
+ )
26
+ from ciris_engine.schemas.runtime.system_context import ContinuitySummary, TelemetrySummary
27
+ from ciris_engine.schemas.services.graph.telemetry import MetricAggregates, MetricRecord
28
+
29
+ # TypeVar for summary cache
30
+ SummaryType = TypeVar("SummaryType", TelemetrySummary, ContinuitySummary)
31
+
32
+ if TYPE_CHECKING:
33
+ from ciris_engine.logic.buses.memory_bus import MemoryBus
34
+ from ciris_engine.logic.buses.runtime_control_bus import RuntimeControlBus
35
+ from ciris_engine.logic.services.graph.telemetry_service.service import GraphTelemetryService
36
+ from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
37
+
38
+ # Metric types to query - moved from inline definition
39
+ METRIC_TYPES = [
40
+ ("llm.tokens.total", "tokens"),
41
+ ("llm_tokens_used", "tokens"), # Legacy metric name
42
+ ("llm.tokens.input", "tokens"),
43
+ ("llm.tokens.output", "tokens"),
44
+ ("llm.cost.cents", "cost"),
45
+ ("llm.environmental.carbon_grams", "carbon"),
46
+ ("llm.environmental.energy_kwh", "energy"),
47
+ ("llm.latency.ms", "latency"),
48
+ ("thought_processing_completed", "thoughts"),
49
+ ("thought_processing_started", "thoughts"),
50
+ ("action_selected_task_complete", "tasks"),
51
+ ("handler_invoked_total", "messages"),
52
+ ("error.occurred", "errors"),
53
+ ]
54
+
55
+
56
+ # ============================================================================
57
+ # METRIC COLLECTION HELPERS
58
+ # ============================================================================
59
+
60
+
61
+ async def collect_metric_aggregates(
62
+ telemetry_service: "GraphTelemetryService",
63
+ metric_types: List[Tuple[str, str]],
64
+ window_start_24h: datetime,
65
+ window_start_1h: datetime,
66
+ window_end: datetime,
67
+ ) -> MetricAggregates:
68
+ """Collect and aggregate metrics across time windows.
69
+
70
+ Args:
71
+ telemetry_service: The telemetry service instance
72
+ metric_types: List of (metric_name, metric_type) tuples to query
73
+ window_start_24h: Start of 24-hour window
74
+ window_start_1h: Start of 1-hour window
75
+ window_end: End of both windows
76
+
77
+ Returns:
78
+ MetricAggregates schema with all collected metrics
79
+
80
+ Raises:
81
+ MetricCollectionError: If metric collection fails
82
+ InvalidMetricDataError: If metric data is invalid
83
+ """
84
+ aggregates = MetricAggregates()
85
+
86
+ try:
87
+ for metric_name, metric_type in metric_types:
88
+ # Get 24h data
89
+ day_metrics: List[MetricRecord] = await telemetry_service.query_metrics(
90
+ metric_name=metric_name, start_time=window_start_24h, end_time=window_end
91
+ )
92
+
93
+ for metric in day_metrics:
94
+ # Aggregate into appropriate counter
95
+ aggregate_metric_by_type(
96
+ metric_type, metric.value, metric.timestamp, metric.tags, aggregates, window_start_1h
97
+ )
98
+
99
+ return aggregates
100
+
101
+ except Exception as e:
102
+ raise MetricCollectionError(f"Failed to collect metric aggregates: {e}") from e
103
+
104
+
105
+ def _update_windowed_metric(
106
+ aggregates: MetricAggregates,
107
+ field_24h: str,
108
+ field_1h: str,
109
+ value: float,
110
+ in_1h_window: bool,
111
+ converter: Callable[[float], Union[int, float]] = float,
112
+ ) -> None:
113
+ """Update a metric with both 24h and 1h windows.
114
+
115
+ Args:
116
+ aggregates: MetricAggregates object to update
117
+ field_24h: Name of 24h field to update
118
+ field_1h: Name of 1h field to update
119
+ value: Value to add
120
+ in_1h_window: Whether metric is in 1h window
121
+ converter: Function to convert value (int or float)
122
+ """
123
+ setattr(aggregates, field_24h, getattr(aggregates, field_24h) + converter(value))
124
+ if in_1h_window:
125
+ setattr(aggregates, field_1h, getattr(aggregates, field_1h) + converter(value))
126
+
127
+
128
+ def _handle_tokens_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
129
+ """Handle tokens metric aggregation."""
130
+ _update_windowed_metric(aggregates, "tokens_24h", "tokens_1h", value, in_1h_window, int)
131
+
132
+
133
+ def _handle_cost_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
134
+ """Handle cost metric aggregation."""
135
+ _update_windowed_metric(aggregates, "cost_24h_cents", "cost_1h_cents", value, in_1h_window, float)
136
+
137
+
138
+ def _handle_carbon_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
139
+ """Handle carbon metric aggregation."""
140
+ _update_windowed_metric(aggregates, "carbon_24h_grams", "carbon_1h_grams", value, in_1h_window, float)
141
+
142
+
143
+ def _handle_energy_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
144
+ """Handle energy metric aggregation."""
145
+ _update_windowed_metric(aggregates, "energy_24h_kwh", "energy_1h_kwh", value, in_1h_window, float)
146
+
147
+
148
+ def _handle_messages_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
149
+ """Handle messages metric aggregation."""
150
+ _update_windowed_metric(aggregates, "messages_24h", "messages_1h", value, in_1h_window, int)
151
+
152
+
153
+ def _handle_thoughts_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
154
+ """Handle thoughts metric aggregation."""
155
+ _update_windowed_metric(aggregates, "thoughts_24h", "thoughts_1h", value, in_1h_window, int)
156
+
157
+
158
+ def _handle_tasks_metric(aggregates: MetricAggregates, value: float) -> None:
159
+ """Handle tasks metric aggregation (24h only, no 1h tracking)."""
160
+ aggregates.tasks_24h += int(value)
161
+
162
+
163
+ def _handle_errors_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool, tags: Dict[str, str]) -> None:
164
+ """Handle errors metric aggregation."""
165
+ _update_windowed_metric(aggregates, "errors_24h", "errors_1h", value, in_1h_window, int)
166
+ # Track errors by service
167
+ service = tags.get("service", "unknown")
168
+ aggregates.service_errors[service] = aggregates.service_errors.get(service, 0) + 1
169
+
170
+
171
+ def _handle_latency_metric(aggregates: MetricAggregates, value: float, tags: Dict[str, str]) -> None:
172
+ """Handle latency metric aggregation (service-level, no time windowing)."""
173
+ service = tags.get("service", "unknown")
174
+ if service not in aggregates.service_latency:
175
+ aggregates.service_latency[service] = []
176
+ aggregates.service_latency[service].append(float(value))
177
+
178
+
179
+ # Handler type definition
180
+ MetricHandlerFunc = Callable[[MetricAggregates, float, bool, Dict[str, str]], None]
181
+
182
+ # Metric type dispatch table
183
+ _METRIC_HANDLERS: Dict[str, MetricHandlerFunc] = {
184
+ "tokens": lambda agg, val, win, tags: _handle_tokens_metric(agg, val, win),
185
+ "cost": lambda agg, val, win, tags: _handle_cost_metric(agg, val, win),
186
+ "carbon": lambda agg, val, win, tags: _handle_carbon_metric(agg, val, win),
187
+ "energy": lambda agg, val, win, tags: _handle_energy_metric(agg, val, win),
188
+ "messages": lambda agg, val, win, tags: _handle_messages_metric(agg, val, win),
189
+ "thoughts": lambda agg, val, win, tags: _handle_thoughts_metric(agg, val, win),
190
+ "tasks": lambda agg, val, win, tags: _handle_tasks_metric(agg, val),
191
+ "errors": lambda agg, val, win, tags: _handle_errors_metric(agg, val, win, tags),
192
+ "latency": lambda agg, val, win, tags: _handle_latency_metric(agg, val, tags),
193
+ }
194
+
195
+
196
+ def aggregate_metric_by_type(
197
+ metric_type: str,
198
+ value: float,
199
+ timestamp: datetime,
200
+ tags: Dict[str, str],
201
+ aggregates: MetricAggregates,
202
+ window_start_1h: datetime,
203
+ ) -> None:
204
+ """Aggregate a single metric value into the appropriate counters.
205
+
206
+ Args:
207
+ metric_type: Type of metric (tokens, cost, carbon, etc.)
208
+ value: Numeric value from metric
209
+ timestamp: When the metric occurred
210
+ tags: Metric tags (service, etc.)
211
+ aggregates: MetricAggregates object to update (mutated)
212
+ window_start_1h: Start of 1-hour window for filtering
213
+
214
+ Raises:
215
+ UnknownMetricTypeError: If metric_type is not recognized
216
+ """
217
+ # Check if timestamp is in 1h window
218
+ in_1h_window = timestamp >= window_start_1h
219
+
220
+ # Dispatch to appropriate handler
221
+ handler = _METRIC_HANDLERS.get(metric_type)
222
+ if not handler:
223
+ raise UnknownMetricTypeError(f"Unknown metric type: {metric_type}")
224
+
225
+ handler(aggregates, value, in_1h_window, tags)
226
+
227
+ # Track service calls
228
+ if "service" in tags:
229
+ service = tags["service"]
230
+ aggregates.service_calls[service] = aggregates.service_calls.get(service, 0) + 1
231
+
232
+
233
+ # ============================================================================
234
+ # EXTERNAL DATA COLLECTION HELPERS
235
+ # ============================================================================
236
+
237
+
238
+ async def get_average_thought_depth(
239
+ memory_bus: Optional["MemoryBus"],
240
+ window_start: datetime,
241
+ ) -> float:
242
+ """Get average thought depth from the last 24 hours.
243
+
244
+ Args:
245
+ memory_bus: Memory bus to access persistence
246
+ window_start: Start of time window
247
+
248
+ Returns:
249
+ Average thought depth (must be valid positive number)
250
+
251
+ Raises:
252
+ MemoryBusUnavailableError: If memory bus not available
253
+ ThoughtDepthQueryError: If database query fails
254
+ NoThoughtDataError: If no thought data available in window
255
+ """
256
+ if not memory_bus:
257
+ raise MemoryBusUnavailableError("Memory bus is not available")
258
+
259
+ try:
260
+ from ciris_engine.logic.persistence import get_db_connection
261
+
262
+ # Get the memory service to access its db_path
263
+ memory_service = await memory_bus.get_service(handler_name="telemetry_service")
264
+ if not memory_service:
265
+ raise MemoryBusUnavailableError("Memory service not found on memory bus")
266
+
267
+ db_path = getattr(memory_service, "db_path", None)
268
+ if not db_path:
269
+ raise ThoughtDepthQueryError("Memory service has no db_path attribute")
270
+
271
+ from ciris_engine.logic.persistence.db.dialect import get_adapter
272
+
273
+ adapter = get_adapter()
274
+
275
+ with get_db_connection(db_path=db_path) as conn:
276
+ cursor = conn.cursor()
277
+ # Use window_start parameter for consistent timing with other telemetry calculations
278
+ # Use dialect-appropriate placeholder
279
+ sql = f"""
280
+ SELECT AVG(thought_depth) as avg_depth
281
+ FROM thoughts
282
+ WHERE created_at >= {adapter.placeholder()}
283
+ """
284
+ cursor.execute(sql, (window_start.isoformat(),))
285
+ result = cursor.fetchone()
286
+
287
+ # Handle both dict (PostgreSQL RealDictCursor/SQLite Row) and tuple results
288
+ if result:
289
+ if isinstance(result, dict):
290
+ avg_depth = result.get("avg_depth")
291
+ elif hasattr(result, "keys"):
292
+ # SQLite Row or dict-like object
293
+ avg_depth = result["avg_depth"]
294
+ else:
295
+ # Tuple result - first column is avg_depth
296
+ avg_depth = result[0] if result else None
297
+
298
+ if avg_depth is not None:
299
+ return float(avg_depth)
300
+
301
+ raise NoThoughtDataError("No thought data available in the last 24 hours")
302
+
303
+ except NoThoughtDataError:
304
+ raise # Re-raise as-is
305
+ except Exception as e:
306
+ raise ThoughtDepthQueryError(f"Failed to query thought depth: {e}") from e
307
+
308
+
309
+ async def get_queue_saturation(
310
+ runtime_control_bus: Optional["RuntimeControlBus"],
311
+ ) -> float:
312
+ """Get current processor queue saturation (0.0-1.0).
313
+
314
+ Args:
315
+ runtime_control_bus: Runtime control bus to access queue status
316
+
317
+ Returns:
318
+ Queue saturation ratio between 0.0 and 1.0
319
+
320
+ Raises:
321
+ RuntimeControlBusUnavailableError: If runtime control bus not available
322
+ QueueStatusUnavailableError: If queue status cannot be retrieved
323
+ """
324
+ if not runtime_control_bus:
325
+ raise RuntimeControlBusUnavailableError("Runtime control bus is not available")
326
+
327
+ try:
328
+ runtime_control = await runtime_control_bus.get_service(handler_name="telemetry_service")
329
+ if not runtime_control:
330
+ raise RuntimeControlBusUnavailableError("Runtime control service not found on bus")
331
+
332
+ processor_queue_status = await runtime_control.get_processor_queue_status()
333
+ if not processor_queue_status:
334
+ raise QueueStatusUnavailableError("get_processor_queue_status returned None")
335
+
336
+ if processor_queue_status.max_size <= 0:
337
+ raise QueueStatusUnavailableError(f"Invalid max_size: {processor_queue_status.max_size}")
338
+
339
+ queue_saturation = processor_queue_status.queue_size / processor_queue_status.max_size
340
+ # Clamp to 0-1 range
341
+ return float(min(1.0, max(0.0, queue_saturation)))
342
+
343
+ except (RuntimeControlBusUnavailableError, QueueStatusUnavailableError):
344
+ raise # Re-raise as-is
345
+ except Exception as e:
346
+ raise QueueStatusUnavailableError(f"Failed to get queue saturation: {e}") from e
347
+
348
+
349
+ def get_service_uptime(
350
+ start_time: Optional[datetime],
351
+ now: datetime,
352
+ ) -> float:
353
+ """Get service uptime in seconds.
354
+
355
+ Args:
356
+ start_time: When the service started (or None)
357
+ now: Current time
358
+
359
+ Returns:
360
+ Uptime in seconds
361
+
362
+ Raises:
363
+ ServiceStartTimeUnavailableError: If start_time is None
364
+ """
365
+ if start_time is None:
366
+ raise ServiceStartTimeUnavailableError("Service start_time has not been set")
367
+
368
+ return (now - start_time).total_seconds()
369
+
370
+
371
+ # ============================================================================
372
+ # CALCULATION HELPERS
373
+ # ============================================================================
374
+
375
+
376
+ def calculate_error_rate(
377
+ errors_24h: int,
378
+ total_operations: int,
379
+ ) -> float:
380
+ """Calculate error rate percentage.
381
+
382
+ Args:
383
+ errors_24h: Number of errors in 24h window
384
+ total_operations: Total operations (messages + thoughts + tasks)
385
+
386
+ Returns:
387
+ Error rate as percentage (0.0-100.0)
388
+ """
389
+ if total_operations == 0:
390
+ return 0.0
391
+ return (errors_24h / total_operations) * 100.0
392
+
393
+
394
+ def calculate_average_latencies(
395
+ service_latency: Dict[str, List[float]],
396
+ ) -> Dict[str, float]:
397
+ """Calculate average latency per service.
398
+
399
+ Args:
400
+ service_latency: Map of service name to list of latency values
401
+
402
+ Returns:
403
+ Map of service name to average latency in ms
404
+ """
405
+ result = {}
406
+ for service, latencies in service_latency.items():
407
+ if latencies:
408
+ result[service] = sum(latencies) / len(latencies)
409
+ return result
410
+
411
+
412
+ # ============================================================================
413
+ # CACHE HELPERS
414
+ # ============================================================================
415
+
416
+
417
+ def check_summary_cache(
418
+ cache: Dict[str, Tuple[datetime, Any]],
419
+ cache_key: str,
420
+ now: datetime,
421
+ ttl_seconds: int,
422
+ ) -> Optional[Any]:
423
+ """Check if cached summary is still valid.
424
+
425
+ Args:
426
+ cache: Summary cache dictionary
427
+ cache_key: Key to look up in cache
428
+ now: Current time
429
+ ttl_seconds: Cache TTL in seconds
430
+
431
+ Returns:
432
+ Cached summary (TelemetrySummary or ContinuitySummary) if valid, None otherwise
433
+ """
434
+ if cache_key in cache:
435
+ cached_time, cached_summary = cache[cache_key]
436
+ if (now - cached_time).total_seconds() < ttl_seconds:
437
+ return cached_summary
438
+ return None
439
+
440
+
441
+ def store_summary_cache(
442
+ cache: Dict[str, Tuple[datetime, Any]],
443
+ cache_key: str,
444
+ now: datetime,
445
+ summary: Any,
446
+ ) -> None:
447
+ """Store summary in cache.
448
+
449
+ Args:
450
+ cache: Summary cache dictionary (mutated)
451
+ cache_key: Key to store under
452
+ now: Current time
453
+ summary: Summary to cache
454
+ """
455
+ cache[cache_key] = (now, summary)
456
+
457
+
458
+ # ============================================================================
459
+ # SCHEMA BUILDERS
460
+ # ============================================================================
461
+
462
+
463
+ def _extract_service_stats_cb_data(stats: JSONDict) -> "CircuitBreakerState":
464
+ """Extract circuit breaker data from service stats dict.
465
+
466
+ Args:
467
+ stats: Service stats dict containing circuit_breaker_state
468
+
469
+ Returns:
470
+ CircuitBreakerState with state and metrics
471
+ """
472
+ # Import at runtime to avoid circular dependency
473
+ from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
474
+
475
+ return CircuitBreakerState(
476
+ state=stats.get("circuit_breaker_state", "unknown"),
477
+ total_requests=stats.get("total_requests", 0),
478
+ failed_requests=stats.get("failed_requests", 0),
479
+ failure_rate=stats.get("failure_rate", "0.00%"),
480
+ consecutive_failures=stats.get("consecutive_failures", 0),
481
+ failure_count=stats.get("consecutive_failures", 0),
482
+ success_count=0,
483
+ )
484
+
485
+
486
+ def _extract_direct_cb_data(cb: Any) -> "CircuitBreakerState":
487
+ """Extract circuit breaker data from CircuitBreaker object.
488
+
489
+ Args:
490
+ cb: CircuitBreaker instance
491
+
492
+ Returns:
493
+ CircuitBreakerState with state and counts
494
+ """
495
+ from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
496
+
497
+ return CircuitBreakerState(
498
+ state=str(cb.state) if hasattr(cb, "state") else "unknown",
499
+ failure_count=cb.failure_count if hasattr(cb, "failure_count") else 0,
500
+ success_count=cb.success_count if hasattr(cb, "success_count") else 0,
501
+ total_requests=0,
502
+ failed_requests=0,
503
+ consecutive_failures=cb.failure_count if hasattr(cb, "failure_count") else 0,
504
+ failure_rate="0.00%",
505
+ )
506
+
507
+
508
+ def _collect_from_service_stats(bus: Any) -> Dict[str, "CircuitBreakerState"]:
509
+ """Collect circuit breaker data from bus.get_service_stats().
510
+
511
+ Args:
512
+ bus: Bus instance with get_service_stats method
513
+
514
+ Returns:
515
+ Dict mapping service names to their circuit breaker state
516
+ """
517
+ from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
518
+
519
+ cb_data: Dict[str, CircuitBreakerState] = {}
520
+
521
+ try:
522
+ service_stats = bus.get_service_stats()
523
+ if not isinstance(service_stats, dict):
524
+ return cb_data
525
+
526
+ for svc_name, stats in service_stats.items():
527
+ if isinstance(stats, dict) and "circuit_breaker_state" in stats:
528
+ cb_data[svc_name] = _extract_service_stats_cb_data(stats)
529
+
530
+ except Exception:
531
+ # Silently skip buses that fail to provide stats
532
+ pass
533
+
534
+ return cb_data
535
+
536
+
537
+ def _collect_from_direct_cb_attribute(
538
+ bus: Any, existing_data: Dict[str, "CircuitBreakerState"]
539
+ ) -> Dict[str, "CircuitBreakerState"]:
540
+ """Collect circuit breaker data from bus.circuit_breakers attribute.
541
+
542
+ Args:
543
+ bus: Bus instance with circuit_breakers attribute
544
+ existing_data: Already collected CB data (don't override these)
545
+
546
+ Returns:
547
+ Dict mapping service names to their circuit breaker state
548
+ """
549
+ from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
550
+
551
+ cb_data: Dict[str, CircuitBreakerState] = {}
552
+
553
+ try:
554
+ circuit_breakers = bus.circuit_breakers
555
+ if not isinstance(circuit_breakers, dict):
556
+ return cb_data
557
+
558
+ for cb_name, cb in circuit_breakers.items():
559
+ if cb_name not in existing_data: # Don't override if already collected
560
+ cb_data[cb_name] = _extract_direct_cb_data(cb)
561
+
562
+ except Exception:
563
+ # Silently skip
564
+ pass
565
+
566
+ return cb_data
567
+
568
+
569
+ def _collect_from_single_bus(bus: Any) -> Dict[str, "CircuitBreakerState"]:
570
+ """Collect circuit breaker data from a single bus.
571
+
572
+ Args:
573
+ bus: Bus instance to collect from
574
+
575
+ Returns:
576
+ Dict mapping service names to their circuit breaker state
577
+ """
578
+ from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
579
+
580
+ cb_data: Dict[str, CircuitBreakerState] = {}
581
+
582
+ # Try get_service_stats first
583
+ if hasattr(bus, "get_service_stats"):
584
+ logger.debug("[CB COLLECT] Bus has get_service_stats method")
585
+ cb_data.update(_collect_from_service_stats(bus))
586
+ logger.debug(f"[CB COLLECT] Collected {len(cb_data)} CBs from service_stats")
587
+
588
+ # Also check direct circuit_breakers attribute
589
+ if hasattr(bus, "circuit_breakers"):
590
+ cb_attr = getattr(bus, "circuit_breakers", {})
591
+ logger.debug(
592
+ f"[CB COLLECT] Bus has circuit_breakers attribute with {len(cb_attr) if isinstance(cb_attr, dict) else 0} entries"
593
+ )
594
+ cb_data.update(_collect_from_direct_cb_attribute(bus, cb_data))
595
+ logger.debug(f"[CB COLLECT] Total {len(cb_data)} CBs after checking circuit_breakers attribute")
596
+
597
+ return cb_data
598
+
599
+
600
+ def collect_circuit_breaker_state(runtime: Any) -> Dict[str, "CircuitBreakerState"]:
601
+ """Collect circuit breaker state from all buses.
602
+
603
+ Walks through all buses (LLM, Memory, Communication, Tool, Wise, RuntimeControl)
604
+ via the runtime's bus_manager and collects their circuit breaker states.
605
+
606
+ Args:
607
+ runtime: Runtime instance with bus_manager attribute
608
+
609
+ Returns:
610
+ Dict mapping service names to their circuit breaker state
611
+ """
612
+ from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
613
+
614
+ circuit_breaker_data: Dict[str, CircuitBreakerState] = {}
615
+
616
+ if not runtime:
617
+ logger.debug("[CB COLLECT] No runtime provided")
618
+ return circuit_breaker_data
619
+
620
+ try:
621
+ bus_manager = getattr(runtime, "bus_manager", None)
622
+ if not bus_manager:
623
+ logger.debug(f"[CB COLLECT] Runtime has no bus_manager (type: {type(runtime).__name__})")
624
+ return circuit_breaker_data
625
+
626
+ # List of bus attributes to check
627
+ bus_names = ["llm", "memory", "communication", "wise", "tool", "runtime_control"]
628
+
629
+ for bus_name in bus_names:
630
+ bus = getattr(bus_manager, bus_name, None)
631
+ if bus:
632
+ logger.debug(f"[CB COLLECT] Collecting from {bus_name} bus ({type(bus).__name__})")
633
+ bus_data = _collect_from_single_bus(bus)
634
+ if bus_data:
635
+ logger.debug(f"[CB COLLECT] Found {len(bus_data)} circuit breakers in {bus_name} bus")
636
+ circuit_breaker_data.update(bus_data)
637
+ else:
638
+ logger.debug(f"[CB COLLECT] No {bus_name} bus in bus_manager")
639
+
640
+ logger.debug(f"[CB COLLECT] Total circuit breakers collected: {len(circuit_breaker_data)}")
641
+
642
+ except Exception as e:
643
+ # If anything fails, return whatever we collected so far
644
+ logger.warning(f"[CB COLLECT] Error collecting circuit breakers: {e}")
645
+
646
+ return circuit_breaker_data
647
+
648
+
649
+ def build_telemetry_summary(
650
+ window_start: datetime,
651
+ window_end: datetime,
652
+ uptime_seconds: float,
653
+ aggregates: MetricAggregates,
654
+ error_rate: float,
655
+ avg_thought_depth: float,
656
+ queue_saturation: float,
657
+ service_latency_ms: Dict[str, float],
658
+ circuit_breaker: Optional[Dict[str, "CircuitBreakerState"]] = None,
659
+ ) -> TelemetrySummary:
660
+ """Build TelemetrySummary from collected data.
661
+
662
+ Args:
663
+ window_start: Start of time window
664
+ window_end: End of time window
665
+ uptime_seconds: Service uptime
666
+ aggregates: Collected metric aggregates
667
+ error_rate: Calculated error rate percentage
668
+ avg_thought_depth: Average thought depth
669
+ queue_saturation: Queue saturation ratio
670
+ service_latency_ms: Service latency map
671
+ circuit_breaker: Circuit breaker state across all services
672
+
673
+ Returns:
674
+ Validated TelemetrySummary schema
675
+ """
676
+ return TelemetrySummary(
677
+ window_start=window_start,
678
+ window_end=window_end,
679
+ uptime_seconds=uptime_seconds,
680
+ messages_processed_24h=aggregates.messages_24h,
681
+ thoughts_processed_24h=aggregates.thoughts_24h,
682
+ tasks_completed_24h=aggregates.tasks_24h,
683
+ errors_24h=aggregates.errors_24h,
684
+ messages_current_hour=aggregates.messages_1h,
685
+ thoughts_current_hour=aggregates.thoughts_1h,
686
+ errors_current_hour=aggregates.errors_1h,
687
+ service_calls=aggregates.service_calls,
688
+ service_errors=aggregates.service_errors,
689
+ service_latency_ms=service_latency_ms,
690
+ tokens_last_hour=float(aggregates.tokens_1h),
691
+ cost_last_hour_cents=aggregates.cost_1h_cents,
692
+ carbon_last_hour_grams=aggregates.carbon_1h_grams,
693
+ energy_last_hour_kwh=aggregates.energy_1h_kwh,
694
+ tokens_24h=float(aggregates.tokens_24h),
695
+ cost_24h_cents=aggregates.cost_24h_cents,
696
+ carbon_24h_grams=aggregates.carbon_24h_grams,
697
+ energy_24h_kwh=aggregates.energy_24h_kwh,
698
+ error_rate_percent=error_rate,
699
+ avg_thought_depth=avg_thought_depth,
700
+ queue_saturation=queue_saturation,
701
+ circuit_breaker=circuit_breaker,
702
+ )
703
+
704
+
705
+ # =============================================================================
706
+ # QUERY_METRICS HELPERS (CC 22 → 6 reduction)
707
+ # =============================================================================
708
+
709
+
710
+ def calculate_query_time_window(start_time: Optional[datetime], end_time: Optional[datetime], now: datetime) -> int:
711
+ """
712
+ Calculate hours for query time window.
713
+
714
+ Args:
715
+ start_time: Optional start of time range
716
+ end_time: Optional end of time range
717
+ now: Current time
718
+
719
+ Returns:
720
+ Number of hours for the query window (default 24)
721
+ """
722
+ if start_time and end_time:
723
+ return int((end_time - start_time).total_seconds() / 3600)
724
+ elif start_time:
725
+ return int((now - start_time).total_seconds() / 3600)
726
+ return 24 # Default
727
+
728
+
729
+ def filter_by_metric_name(data: object, metric_name: str) -> bool:
730
+ """
731
+ Check if timeseries data matches the requested metric name.
732
+
733
+ Args:
734
+ data: Timeseries data point with metric_name attribute
735
+ metric_name: Name of metric to match
736
+
737
+ Returns:
738
+ True if data matches metric name
739
+ """
740
+ return getattr(data, "metric_name", None) == metric_name
741
+
742
+
743
+ def filter_by_tags(data: object, tags: Optional[Dict[str, str]]) -> bool:
744
+ """
745
+ Check if timeseries data matches all required tags.
746
+
747
+ Args:
748
+ data: Timeseries data point with tags or labels attribute
749
+ tags: Optional dictionary of tags to match
750
+
751
+ Returns:
752
+ True if data matches all tags (or tags is None)
753
+ """
754
+ if not tags:
755
+ return True
756
+
757
+ # Check both 'tags' and 'labels' attributes
758
+ # Note: 'tags' may be a list, 'labels' is the dict we want for key-value filtering
759
+ data_tags = getattr(data, "tags", None)
760
+ if not isinstance(data_tags, dict):
761
+ data_tags = getattr(data, "labels", None)
762
+ if not isinstance(data_tags, dict):
763
+ data_tags = {}
764
+
765
+ return all(data_tags.get(k) == v for k, v in tags.items())
766
+
767
+
768
+ def filter_by_time_range(data: object, start_time: Optional[datetime], end_time: Optional[datetime]) -> bool:
769
+ """
770
+ Check if timeseries data timestamp is within the specified range.
771
+
772
+ Args:
773
+ data: Timeseries data point with timestamp/start_time attribute
774
+ start_time: Optional start of time range
775
+ end_time: Optional end of time range
776
+
777
+ Returns:
778
+ True if timestamp is within range (or no range specified)
779
+ """
780
+ # Try timestamp first, fall back to start_time (used by TSDBGraphNode)
781
+ timestamp = getattr(data, "timestamp", None) or getattr(data, "start_time", None)
782
+ if not timestamp:
783
+ return False
784
+
785
+ if start_time and timestamp < start_time:
786
+ return False
787
+
788
+ if end_time and timestamp > end_time:
789
+ return False
790
+
791
+ return True
792
+
793
+
794
+ def convert_to_metric_record(data: object) -> Optional[MetricRecord]:
795
+ """
796
+ Convert timeseries data to typed MetricRecord.
797
+
798
+ Args:
799
+ data: Timeseries data point
800
+
801
+ Returns:
802
+ MetricRecord if data is valid, None otherwise
803
+ """
804
+ metric_name = getattr(data, "metric_name", None)
805
+ value = getattr(data, "value", None)
806
+ # Try timestamp first, fall back to start_time (used by TSDBGraphNode)
807
+ timestamp = getattr(data, "timestamp", None) or getattr(data, "start_time", None)
808
+
809
+ # Validate required fields
810
+ if not (metric_name and value is not None and timestamp):
811
+ return None
812
+
813
+ # Check both 'tags' and 'labels' attributes
814
+ # Note: 'tags' may be a list, 'labels' is the dict we want for metadata
815
+ tags = getattr(data, "tags", None)
816
+ if not isinstance(tags, dict):
817
+ tags = getattr(data, "labels", None)
818
+ if not isinstance(tags, dict):
819
+ tags = {}
820
+
821
+ return MetricRecord(
822
+ metric_name=metric_name,
823
+ value=value,
824
+ timestamp=timestamp,
825
+ tags=tags,
826
+ )
827
+
828
+
829
+ # =============================================================================
830
+ # _TRY_COLLECT_METRICS HELPERS (CC 19 → 6 reduction)
831
+ # =============================================================================
832
+
833
+
834
+ def should_retry_metric_collection(attempt: int, max_retries: int) -> bool:
835
+ """
836
+ Determine if metric collection should be retried.
837
+
838
+ Args:
839
+ attempt: Current attempt number (0-indexed)
840
+ max_retries: Maximum number of retries allowed
841
+
842
+ Returns:
843
+ True if should retry
844
+ """
845
+ return attempt < max_retries
846
+
847
+
848
+ def calculate_retry_delay(attempt: int, base_delay: float = 0.1) -> float:
849
+ """
850
+ Calculate exponential backoff delay for retry.
851
+
852
+ Args:
853
+ attempt: Current attempt number (0-indexed)
854
+ base_delay: Base delay in seconds
855
+
856
+ Returns:
857
+ Delay in seconds
858
+ """
859
+ return float(base_delay * (2**attempt))
860
+
861
+
862
+ def validate_collected_metrics(metrics: object) -> bool:
863
+ """
864
+ Validate that collected metrics are in expected format.
865
+
866
+ Args:
867
+ metrics: Metrics data to validate
868
+
869
+ Returns:
870
+ True if metrics are valid
871
+ """
872
+ if metrics is None:
873
+ return False
874
+
875
+ # Check if it's a dictionary with expected structure
876
+ if isinstance(metrics, dict):
877
+ return True
878
+
879
+ # Check if it's an object with attributes
880
+ if hasattr(metrics, "__dict__"):
881
+ return True
882
+
883
+ return False
884
+
885
+
886
+ # =============================================================================
887
+ # COLLECT_FROM_ADAPTER_INSTANCES HELPERS (CC 19 → 6 reduction)
888
+ # =============================================================================
889
+
890
+
891
+ def extract_adapter_name(adapter: object) -> str:
892
+ """
893
+ Extract adapter name from adapter instance.
894
+
895
+ Args:
896
+ adapter: Adapter instance
897
+
898
+ Returns:
899
+ Adapter name string
900
+ """
901
+ if hasattr(adapter, "adapter_name"):
902
+ return str(adapter.adapter_name)
903
+ elif hasattr(adapter, "name"):
904
+ return str(adapter.name)
905
+ elif hasattr(adapter, "__class__"):
906
+ return adapter.__class__.__name__
907
+ return "unknown_adapter"
908
+
909
+
910
+ def is_adapter_healthy(adapter: object) -> bool:
911
+ """
912
+ Check if adapter is in healthy state for metrics collection.
913
+
914
+ Args:
915
+ adapter: Adapter instance
916
+
917
+ Returns:
918
+ True if adapter is healthy
919
+ """
920
+ # Check if adapter has status attribute
921
+ if hasattr(adapter, "status"):
922
+ status = adapter.status
923
+ if hasattr(status, "value"):
924
+ return bool(status.value == "running")
925
+ return str(status).lower() == "running"
926
+
927
+ # If no status, assume healthy
928
+ return True
929
+
930
+
931
+ async def collect_metrics_from_single_adapter(adapter: object) -> Optional[Dict[str, float]]:
932
+ """
933
+ Collect metrics from a single adapter instance.
934
+
935
+ Args:
936
+ adapter: Adapter instance
937
+
938
+ Returns:
939
+ Metrics dictionary or None if collection failed
940
+ """
941
+ try:
942
+ if hasattr(adapter, "get_metrics"):
943
+ metrics = await adapter.get_metrics()
944
+ return metrics if isinstance(metrics, dict) else None
945
+ return None
946
+ except Exception:
947
+ return None
948
+
949
+
950
+ def aggregate_adapter_metrics(collected_metrics: List[Dict[str, float]]) -> Dict[str, float]:
951
+ """
952
+ Aggregate metrics from multiple adapters.
953
+
954
+ Args:
955
+ collected_metrics: List of metrics dictionaries
956
+
957
+ Returns:
958
+ Aggregated metrics dictionary
959
+ """
960
+ aggregated: Dict[str, float] = {}
961
+
962
+ for metrics in collected_metrics:
963
+ if not metrics:
964
+ continue
965
+
966
+ for key, value in metrics.items():
967
+ if key not in aggregated:
968
+ aggregated[key] = value
969
+ elif isinstance(value, (int, float)) and isinstance(aggregated[key], (int, float)):
970
+ # Sum numeric values
971
+ aggregated[key] = aggregated[key] + value
972
+
973
+ return aggregated
974
+
975
+
976
+ # =============================================================================
977
+ # _GENERATE_SEMANTIC_SERVICE_NAME HELPERS (CC 16 → 6 reduction)
978
+ # =============================================================================
979
+
980
+
981
+ # Service name mapping table
982
+ SERVICE_NAME_MAPPING: Dict[str, str] = {
983
+ "memory_service": "Memory Service",
984
+ "config_service": "Configuration Service",
985
+ "telemetry_service": "Telemetry Service",
986
+ "audit_service": "Audit Service",
987
+ "incident_service": "Incident Management Service",
988
+ "tsdb_consolidation_service": "Time-Series Database Consolidation Service",
989
+ "authentication_service": "Authentication Service",
990
+ "resource_monitor": "Resource Monitor",
991
+ "database_maintenance": "Database Maintenance",
992
+ "secrets_service": "Secrets Service",
993
+ "initialization_service": "Initialization Service",
994
+ "shutdown_service": "Shutdown Service",
995
+ "time_service": "Time Service",
996
+ "task_scheduler": "Task Scheduler",
997
+ "wise_authority": "Wise Authority",
998
+ "adaptive_filter": "Adaptive Filter",
999
+ "visibility_service": "Visibility Service",
1000
+ "consent_service": "Consent Service",
1001
+ "self_observation": "Self-Observation Service",
1002
+ "llm_service": "LLM Service",
1003
+ "runtime_control": "Runtime Control",
1004
+ "secrets_tool": "Secrets Tool",
1005
+ }
1006
+
1007
+
1008
+ def generate_semantic_service_name(service_name: str) -> str:
1009
+ """
1010
+ Generate human-readable semantic name for a service.
1011
+
1012
+ Uses a lookup table approach for better maintainability and lower complexity.
1013
+
1014
+ Args:
1015
+ service_name: Technical service name
1016
+
1017
+ Returns:
1018
+ Human-readable service name
1019
+ """
1020
+ # Direct lookup in mapping table
1021
+ if service_name in SERVICE_NAME_MAPPING:
1022
+ return SERVICE_NAME_MAPPING[service_name]
1023
+
1024
+ # Fallback: Convert snake_case to Title Case
1025
+ return service_name.replace("_", " ").title()
1026
+
1027
+
1028
+ def get_service_category(service_name: str) -> str:
1029
+ """
1030
+ Categorize service by type.
1031
+
1032
+ Args:
1033
+ service_name: Service name
1034
+
1035
+ Returns:
1036
+ Service category
1037
+ """
1038
+ graph_services = {"memory", "config", "telemetry", "audit", "incident", "tsdb"}
1039
+ infrastructure = {"authentication", "resource", "database", "secrets"}
1040
+ lifecycle = {"initialization", "shutdown", "time", "task"}
1041
+ governance = {"wise", "adaptive", "visibility", "consent", "observation"}
1042
+
1043
+ name_lower = service_name.lower()
1044
+
1045
+ if any(svc in name_lower for svc in graph_services):
1046
+ return "graph"
1047
+ elif any(svc in name_lower for svc in infrastructure):
1048
+ return "infrastructure"
1049
+ elif any(svc in name_lower for svc in lifecycle):
1050
+ return "lifecycle"
1051
+ elif any(svc in name_lower for svc in governance):
1052
+ return "governance"
1053
+ else:
1054
+ return "runtime"
1055
+
1056
+
1057
+ # ============================================================================
1058
+ # CONTINUITY SUMMARY HELPERS
1059
+ # ============================================================================
1060
+
1061
+
1062
+ def _extract_timestamp_from_node_id(node: Any, prefix: str) -> Optional[datetime]:
1063
+ """Extract timestamp from lifecycle node ID.
1064
+
1065
+ Args:
1066
+ node: Graph node with lifecycle event
1067
+ prefix: Node ID prefix ('startup_' or 'shutdown_')
1068
+
1069
+ Returns:
1070
+ Datetime if successfully extracted, None otherwise
1071
+ """
1072
+ if not hasattr(node, "id") or not node.id.startswith(prefix):
1073
+ return None
1074
+
1075
+ ts_str = node.id.replace(prefix, "")
1076
+ try:
1077
+ return datetime.fromisoformat(ts_str)
1078
+ except (ValueError, TypeError):
1079
+ return None
1080
+
1081
+
1082
+ def _extract_shutdown_reason_from_node(node: Any) -> Optional[str]:
1083
+ """Extract shutdown reason from shutdown node attributes.
1084
+
1085
+ Args:
1086
+ node: Shutdown graph node
1087
+
1088
+ Returns:
1089
+ Shutdown reason string if found, None otherwise
1090
+ """
1091
+ if not hasattr(node, "attributes"):
1092
+ return None
1093
+
1094
+ attrs = node.attributes
1095
+
1096
+ # Handle both dict (NodeAttributes) and object (GraphNodeAttributes) forms
1097
+ if isinstance(attrs, dict):
1098
+ reason = attrs.get("reason")
1099
+ return str(reason) if reason is not None else None
1100
+ elif hasattr(attrs, "reason"):
1101
+ reason = attrs.reason
1102
+ return str(reason) if reason is not None else None
1103
+
1104
+ return None
1105
+
1106
+
1107
+ def _extract_shutdown_consent_from_node(node: Any) -> Optional[str]:
1108
+ """Extract shutdown consent status from shutdown node attributes.
1109
+
1110
+ Args:
1111
+ node: Shutdown graph node
1112
+
1113
+ Returns:
1114
+ Consent status string ('accepted', 'rejected', or 'manual') if found, None otherwise
1115
+ """
1116
+ if not hasattr(node, "attributes"):
1117
+ return None
1118
+
1119
+ attrs = node.attributes
1120
+
1121
+ # Handle both dict (NodeAttributes) and object (GraphNodeAttributes) forms
1122
+ if isinstance(attrs, dict):
1123
+ consent = attrs.get("consent_status")
1124
+ return str(consent) if consent is not None else None
1125
+ elif hasattr(attrs, "consent_status"):
1126
+ consent = attrs.consent_status
1127
+ return str(consent) if consent is not None else None
1128
+
1129
+ return None
1130
+
1131
+
1132
+ def _extract_timestamps_from_nodes(nodes: List[Any], prefix: str) -> List[datetime]:
1133
+ """Extract all valid timestamps from lifecycle nodes.
1134
+
1135
+ Args:
1136
+ nodes: List of graph nodes
1137
+ prefix: Node ID prefix to match
1138
+
1139
+ Returns:
1140
+ List of extracted timestamps
1141
+ """
1142
+ timestamps = []
1143
+ for node in nodes:
1144
+ ts = _extract_timestamp_from_node_id(node, prefix)
1145
+ if ts:
1146
+ timestamps.append(ts)
1147
+ return timestamps
1148
+
1149
+
1150
+ def _merge_and_sort_events(
1151
+ startup_timestamps: List[datetime], shutdown_timestamps: List[datetime]
1152
+ ) -> List[Tuple[str, datetime]]:
1153
+ """Merge startup/shutdown timestamps into sorted event list.
1154
+
1155
+ Args:
1156
+ startup_timestamps: List of startup times
1157
+ shutdown_timestamps: List of shutdown times
1158
+
1159
+ Returns:
1160
+ Sorted list of (event_type, timestamp) tuples
1161
+ """
1162
+ all_events = []
1163
+ for ts in startup_timestamps:
1164
+ all_events.append(("startup", ts))
1165
+ for ts in shutdown_timestamps:
1166
+ all_events.append(("shutdown", ts))
1167
+ all_events.sort(key=lambda x: x[1])
1168
+ return all_events
1169
+
1170
+
1171
+ def _infer_missing_startup(
1172
+ last_shutdown_ts: Optional[datetime], current_shutdown_ts: datetime
1173
+ ) -> Tuple[datetime, float]:
1174
+ """Infer startup time for shutdown without matching startup.
1175
+
1176
+ Args:
1177
+ last_shutdown_ts: Previous shutdown timestamp (None if first shutdown)
1178
+ current_shutdown_ts: Current shutdown timestamp
1179
+
1180
+ Returns:
1181
+ Tuple of (inferred_startup_time, offline_seconds_to_add)
1182
+ """
1183
+ from datetime import timedelta
1184
+
1185
+ if last_shutdown_ts is None:
1186
+ # First shutdown: assume startup 1 minute BEFORE
1187
+ inferred_startup = current_shutdown_ts - timedelta(minutes=1)
1188
+ logger.debug(
1189
+ f"First shutdown at {current_shutdown_ts} without startup, "
1190
+ f"inferring startup 1 minute before at {inferred_startup}"
1191
+ )
1192
+ return inferred_startup, 0.0
1193
+ else:
1194
+ # Subsequent shutdown: assume startup 1 minute AFTER previous shutdown
1195
+ inferred_startup = last_shutdown_ts + timedelta(minutes=1)
1196
+ logger.debug(
1197
+ f"Shutdown at {current_shutdown_ts} without startup after previous shutdown at {last_shutdown_ts}, "
1198
+ f"inferring startup 1 minute after at {inferred_startup}"
1199
+ )
1200
+ return inferred_startup, 60.0 # 1 minute downtime
1201
+
1202
+
1203
+ def _calculate_online_offline_durations(all_events: List[Tuple[str, datetime]]) -> Tuple[float, float]:
1204
+ """Calculate total online/offline durations from lifecycle events.
1205
+
1206
+ Args:
1207
+ all_events: Sorted list of (event_type, timestamp) tuples
1208
+
1209
+ Returns:
1210
+ Tuple of (total_online_seconds, total_offline_seconds)
1211
+ """
1212
+ total_online = 0.0
1213
+ total_offline = 0.0
1214
+ current_session_start = None
1215
+ last_shutdown = None
1216
+
1217
+ for i, (event_type, ts) in enumerate(all_events):
1218
+ if event_type == "startup":
1219
+ current_session_start = ts
1220
+
1221
+ elif event_type == "shutdown":
1222
+ # Infer missing startup if needed
1223
+ if not current_session_start:
1224
+ current_session_start, offline_to_add = _infer_missing_startup(last_shutdown, ts)
1225
+ total_offline += offline_to_add
1226
+
1227
+ # Calculate session duration
1228
+ session_duration = (ts - current_session_start).total_seconds()
1229
+ total_online += session_duration
1230
+
1231
+ # Calculate offline time to next startup
1232
+ if i + 1 < len(all_events) and all_events[i + 1][0] == "startup":
1233
+ next_startup = all_events[i + 1][1]
1234
+ offline_duration = (next_startup - ts).total_seconds()
1235
+ total_offline += offline_duration
1236
+
1237
+ last_shutdown = ts
1238
+ current_session_start = None
1239
+
1240
+ return total_online, total_offline
1241
+
1242
+
1243
+ async def _fetch_lifecycle_nodes(memory_service: Any) -> Tuple[List[Any], List[Any]]:
1244
+ """Fetch startup and shutdown nodes from memory.
1245
+
1246
+ Args:
1247
+ memory_service: Memory service for queries
1248
+
1249
+ Returns:
1250
+ Tuple of (startup_nodes, shutdown_nodes)
1251
+ """
1252
+ from ciris_engine.schemas.services.graph.memory import MemorySearchFilter
1253
+ from ciris_engine.schemas.services.graph_core import GraphScope
1254
+
1255
+ startup_filter = MemorySearchFilter(scope=GraphScope.IDENTITY.value, node_type="agent", limit=1000)
1256
+ startup_nodes = await memory_service.search(query="startup", filters=startup_filter)
1257
+
1258
+ shutdown_filter = MemorySearchFilter(scope=GraphScope.IDENTITY.value, node_type="agent", limit=1000)
1259
+ shutdown_nodes = await memory_service.search(query="shutdown", filters=shutdown_filter)
1260
+
1261
+ return startup_nodes, shutdown_nodes
1262
+
1263
+
1264
+ async def build_continuity_summary_from_memory(
1265
+ memory_service: Optional[Any], time_service: Any, start_time: Optional[datetime]
1266
+ ) -> Optional[ContinuitySummary]:
1267
+ """Build continuity summary from startup/shutdown memory nodes.
1268
+
1269
+ Args:
1270
+ memory_service: Memory service to query for lifecycle events
1271
+ time_service: Time service for current time
1272
+ start_time: Service start time for current session
1273
+
1274
+ Returns:
1275
+ ContinuitySummary if memory service available, None otherwise
1276
+ """
1277
+ if not memory_service:
1278
+ return None
1279
+
1280
+ try:
1281
+ now = time_service.now() if time_service else datetime.now(timezone.utc)
1282
+
1283
+ # Fetch lifecycle nodes
1284
+ startup_nodes, shutdown_nodes = await _fetch_lifecycle_nodes(memory_service)
1285
+
1286
+ # Extract timestamps
1287
+ startup_timestamps = _extract_timestamps_from_nodes(startup_nodes, "startup_")
1288
+ shutdown_timestamps = _extract_timestamps_from_nodes(shutdown_nodes, "shutdown_")
1289
+
1290
+ # Calculate basic metrics
1291
+ first_startup = min(startup_timestamps) if startup_timestamps else None
1292
+ last_shutdown_ts = max(shutdown_timestamps) if shutdown_timestamps else None
1293
+
1294
+ # Extract last shutdown reason and consent status from the most recent shutdown node
1295
+ last_shutdown_reason = None
1296
+ last_shutdown_consent = None
1297
+ if shutdown_nodes and last_shutdown_ts:
1298
+ # Find the shutdown node with the matching timestamp
1299
+ for node in shutdown_nodes:
1300
+ node_ts = _extract_timestamp_from_node_id(node, "shutdown_")
1301
+ if node_ts == last_shutdown_ts:
1302
+ last_shutdown_reason = _extract_shutdown_reason_from_node(node)
1303
+ last_shutdown_consent = _extract_shutdown_consent_from_node(node)
1304
+ break
1305
+
1306
+ # Merge and calculate durations
1307
+ all_events = _merge_and_sort_events(startup_timestamps, shutdown_timestamps)
1308
+ total_online, total_offline = _calculate_online_offline_durations(all_events)
1309
+
1310
+ # Add current session if online
1311
+ current_session_duration = 0.0
1312
+ if start_time:
1313
+ current_session_duration = (now - start_time).total_seconds()
1314
+ total_online += current_session_duration
1315
+
1316
+ # Calculate averages
1317
+ total_shutdowns = len(shutdown_timestamps)
1318
+ avg_online = total_online / (total_shutdowns + 1) if total_shutdowns >= 0 else 0.0
1319
+ avg_offline = total_offline / total_shutdowns if total_shutdowns > 0 else 0.0
1320
+
1321
+ return ContinuitySummary(
1322
+ first_startup=first_startup,
1323
+ total_time_online_seconds=total_online,
1324
+ total_time_offline_seconds=total_offline,
1325
+ total_shutdowns=total_shutdowns,
1326
+ average_time_online_seconds=avg_online,
1327
+ average_time_offline_seconds=avg_offline,
1328
+ current_session_start=start_time,
1329
+ current_session_duration_seconds=current_session_duration,
1330
+ last_shutdown=last_shutdown_ts,
1331
+ last_shutdown_reason=last_shutdown_reason,
1332
+ last_shutdown_consent=last_shutdown_consent,
1333
+ )
1334
+
1335
+ except Exception as e:
1336
+ logger.warning(f"Failed to build continuity summary: {e}")
1337
+ return None