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,1675 @@
1
+ """
2
+ Consolidated Graph Audit Service
3
+
4
+ Combines functionality from:
5
+ - AuditService (file-based)
6
+ - SignedAuditService (cryptographic signatures)
7
+ - GraphAuditService (graph-based storage)
8
+
9
+ This service provides:
10
+ 1. Graph-based storage (everything is memory)
11
+ 2. Optional file export for compliance
12
+ 3. Cryptographic hash chain for tamper evidence
13
+ 4. Unified interface for all audit operations
14
+ """
15
+
16
+ import asyncio
17
+ import json
18
+ import logging
19
+ import sqlite3
20
+ import sys
21
+ from datetime import datetime
22
+ from pathlib import Path
23
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
24
+ from uuid import uuid4
25
+
26
+ from ciris_engine.logic.persistence.db.dialect import get_adapter
27
+ from ciris_engine.logic.persistence.db.query_builder import ConflictResolution
28
+ from ciris_engine.logic.utils.jsondict_helpers import get_int, get_str
29
+ from ciris_engine.schemas.types import JSONDict
30
+
31
+ # Optional import for psutil
32
+ try:
33
+ import psutil
34
+
35
+ PSUTIL_AVAILABLE = True
36
+ except ImportError:
37
+ psutil = None # type: ignore
38
+ PSUTIL_AVAILABLE = False
39
+
40
+ # SQLite PRAGMA constants (avoid duplicate literals)
41
+ PRAGMA_JOURNAL_MODE_WAL = "PRAGMA journal_mode=WAL"
42
+ PRAGMA_BUSY_TIMEOUT_5000 = "PRAGMA busy_timeout=5000"
43
+ PRAGMA_SYNCHRONOUS_NORMAL = "PRAGMA synchronous=NORMAL"
44
+
45
+ if TYPE_CHECKING:
46
+ from ciris_engine.logic.registries.base import ServiceRegistry
47
+ from ciris_engine.schemas.audit.core import EventPayload, AuditLogEntry
48
+
49
+ from ciris_engine.constants import UTC_TIMEZONE_SUFFIX
50
+ from ciris_engine.logic.audit.hash_chain import AuditHashChain
51
+ from ciris_engine.logic.audit.verifier import AuditVerifier
52
+ from ciris_engine.logic.buses.memory_bus import MemoryBus
53
+ from ciris_engine.logic.services.base_graph_service import BaseGraphService
54
+ from ciris_engine.protocols.infrastructure.base import RegistryAwareServiceProtocol, ServiceRegistryProtocol
55
+ from ciris_engine.protocols.services import AuditService as AuditServiceProtocol
56
+ from ciris_engine.protocols.services.lifecycle.time import TimeServiceProtocol
57
+ from ciris_engine.schemas.audit.hash_chain import AuditEntryResult
58
+ from ciris_engine.schemas.runtime.audit import AuditActionContext, AuditRequest
59
+ from ciris_engine.schemas.runtime.enums import HandlerActionType, ServiceType
60
+ from ciris_engine.schemas.runtime.memory import TimeSeriesDataPoint
61
+ from ciris_engine.schemas.services.graph.audit import AuditEventData, AuditQuery, VerificationReport
62
+
63
+ # TSDB functionality integrated into graph nodes
64
+ from ciris_engine.schemas.services.graph_core import GraphNode, GraphScope, NodeType
65
+ from ciris_engine.schemas.services.nodes import AuditEntry as AuditEntryNode
66
+ from ciris_engine.schemas.services.nodes import AuditEntryContext
67
+ from ciris_engine.schemas.services.operations import MemoryOpStatus, MemoryQuery
68
+
69
+ # Type alias for protocol compatibility
70
+ AuditEntry = AuditEntryNode
71
+
72
+ logger = logging.getLogger(__name__)
73
+
74
+ try:
75
+ from ciris_engine.logic.audit.signature_manager import AuditSignatureManager
76
+ except ImportError as e:
77
+ logger.error(f"Failed to import AuditSignatureManager: {e}")
78
+ raise
79
+
80
+
81
+ class GraphAuditService(BaseGraphService, AuditServiceProtocol, RegistryAwareServiceProtocol):
82
+ """
83
+ Consolidated audit service that stores all audit entries in the graph.
84
+
85
+ Features:
86
+ - Primary storage in graph (everything is memory)
87
+ - Optional file export for compliance
88
+ - Cryptographic hash chain for integrity
89
+ - Digital signatures for non-repudiation
90
+ - Unified interface for all audit operations
91
+ """
92
+
93
+ def __init__(
94
+ self,
95
+ memory_bus: Optional[MemoryBus] = None,
96
+ time_service: Optional[TimeServiceProtocol] = None,
97
+ # File export options
98
+ export_path: Optional[str] = None,
99
+ export_format: str = "jsonl", # jsonl, csv, or sqlite
100
+ # Hash chain options
101
+ enable_hash_chain: bool = True,
102
+ db_path: str = "ciris_audit.db",
103
+ key_path: str = "audit_keys",
104
+ # Retention options
105
+ retention_days: int = 90,
106
+ cache_size: int = 1000,
107
+ ) -> None:
108
+ """
109
+ Initialize the consolidated audit service.
110
+
111
+ Args:
112
+ memory_bus: Bus for graph storage operations
113
+ time_service: Time service for consistent timestamps
114
+ export_path: Optional path for file exports
115
+ export_format: Format for exports (jsonl, csv, sqlite)
116
+ enable_hash_chain: Whether to maintain cryptographic hash chain
117
+ db_path: Path for hash chain database
118
+ key_path: Directory for signing keys
119
+ retention_days: How long to retain audit data
120
+ cache_size: Size of in-memory cache
121
+ """
122
+ if not time_service:
123
+ raise RuntimeError("CRITICAL: TimeService is required for GraphAuditService")
124
+
125
+ # Initialize BaseGraphService with version 2.0.0
126
+ super().__init__(memory_bus=memory_bus, time_service=time_service, version="2.0.0")
127
+
128
+ self._service_registry: Optional[ServiceRegistryProtocol] = None
129
+
130
+ # Export configuration
131
+ self.export_path = Path(export_path) if export_path else None
132
+ self.export_format = export_format
133
+
134
+ # Hash chain configuration
135
+ self.enable_hash_chain = enable_hash_chain
136
+ # For PostgreSQL, keep connection string as-is; for SQLite, ensure Path object
137
+ self.db_path: str | Path
138
+ if db_path.startswith(("postgresql://", "postgres://")):
139
+ self.db_path = db_path
140
+ else:
141
+ self.db_path = Path(db_path)
142
+ self.key_path = Path(key_path)
143
+
144
+ # Retention configuration
145
+ self.retention_days = retention_days
146
+
147
+ # Cache for recent entries
148
+ self._recent_entries: List[AuditRequest] = []
149
+ self._max_cached_entries = cache_size
150
+
151
+ # Hash chain components
152
+ self.hash_chain: Optional[AuditHashChain] = None
153
+ self.signature_manager: Optional[AuditSignatureManager] = None
154
+ self.verifier: Optional[AuditVerifier] = None
155
+ self._db_connection: Optional[sqlite3.Connection] = None
156
+
157
+ # Export buffer
158
+ self._export_buffer: List[AuditRequest] = []
159
+ self._export_task: Optional[asyncio.Task[None]] = None
160
+
161
+ # Memory tracking
162
+ self._process = psutil.Process() if PSUTIL_AVAILABLE else None
163
+
164
+ # Track uptime
165
+ self._start_time: Optional[datetime] = None
166
+
167
+ # Lock for hash chain operations
168
+ self._hash_chain_lock = asyncio.Lock()
169
+
170
+ async def attach_registry(self, registry: "ServiceRegistryProtocol") -> None:
171
+ """
172
+ Attach service registry for bus and service discovery.
173
+
174
+ Implements RegistryAwareServiceProtocol to enable proper initialization
175
+ of memory bus dependency.
176
+
177
+ Args:
178
+ registry: Service registry providing access to buses and services
179
+ """
180
+ self._service_registry = registry
181
+
182
+ if not self._memory_bus and self._service_registry and self._time_service:
183
+ try:
184
+ from ciris_engine.logic.buses import MemoryBus
185
+
186
+ self._memory_bus = MemoryBus(self._service_registry, self._time_service)
187
+ except Exception as e:
188
+ logger.error(f"Failed to initialize memory bus: {e}")
189
+
190
+ async def start(self) -> None:
191
+ """Start the audit service."""
192
+ # Don't call super() as BaseService has async start
193
+ self._started = True
194
+
195
+ logger.info("Starting consolidated GraphAuditService")
196
+
197
+ # Set start time
198
+ if self._time_service:
199
+ self._start_time = self._time_service.now()
200
+ else:
201
+ self._start_time = datetime.now()
202
+
203
+ # Initialize hash chain if enabled
204
+ if self.enable_hash_chain:
205
+ await self._initialize_hash_chain()
206
+
207
+ # Create export directory if needed
208
+ if self.export_path:
209
+ self.export_path.parent.mkdir(parents=True, exist_ok=True)
210
+
211
+ # Start export task if configured
212
+ if self.export_path:
213
+ self._export_task = asyncio.create_task(self._export_worker())
214
+
215
+ logger.info("GraphAuditService started - all audit data flows through graph")
216
+
217
+ async def stop(self) -> None:
218
+ """Stop the audit service."""
219
+ # Flush export buffer
220
+ if self._export_buffer:
221
+ await self._flush_exports()
222
+
223
+ # Cancel export task
224
+ if self._export_task:
225
+ self._export_task.cancel()
226
+ try:
227
+ await self._export_task
228
+ except asyncio.CancelledError:
229
+ # Re-raise after cleanup as per asyncio best practices
230
+ raise
231
+
232
+ # Log final shutdown event BEFORE closing database
233
+ from ciris_engine.schemas.audit.core import EventPayload
234
+
235
+ shutdown_event = EventPayload(
236
+ action="shutdown",
237
+ service_name="audit_service",
238
+ user_id="system",
239
+ result="success",
240
+ )
241
+ try:
242
+ await self.log_event("audit_service_shutdown", shutdown_event)
243
+ except Exception as e:
244
+ logger.warning(f"Failed to log shutdown event: {e}")
245
+
246
+ # Close database connection AFTER logging
247
+ if self._db_connection:
248
+ self._db_connection.close()
249
+
250
+ logger.info("GraphAuditService stopped")
251
+
252
+ # Don't call super() as BaseService has async stop
253
+ self._started = False
254
+
255
+ async def log_action(
256
+ self, action_type: HandlerActionType, context: AuditActionContext, outcome: Optional[str] = None
257
+ ) -> AuditEntryResult:
258
+ """Log an action and return audit entry with hash chain data (REQUIRED)."""
259
+ # Create audit entry
260
+ import json
261
+
262
+ from ciris_engine.schemas.audit.hash_chain import AuditEntryResult
263
+
264
+ logger.info(
265
+ f"DEBUG: log_action called with action_type={action_type.value}, context.parameters={context.parameters}"
266
+ )
267
+
268
+ # Serialize parameters dict to JSON string for AuditRequest (Dict[str, str] requirement)
269
+ parameters_json = json.dumps(context.parameters) if context.parameters else "{}"
270
+
271
+ entry = AuditRequest(
272
+ entry_id=str(uuid4()),
273
+ timestamp=self._time_service.now() if self._time_service else datetime.now(),
274
+ entity_id=context.thought_id,
275
+ event_type=action_type.value,
276
+ actor=context.handler_name or "system",
277
+ details={
278
+ "action_type": action_type.value,
279
+ "thought_id": context.thought_id,
280
+ "task_id": context.task_id,
281
+ "handler_name": context.handler_name,
282
+ "metadata": str(getattr(context, "metadata", {})),
283
+ "parameters": parameters_json, # JSON-serialized parameters (e.g., {"tool_name": "reddit_submit_post"})
284
+ },
285
+ outcome=outcome,
286
+ )
287
+
288
+ logger.debug(f"Created AuditRequest with details.parameters={entry.details.get('parameters')}")
289
+
290
+ # Add to hash chain FIRST (REQUIRED in production)
291
+ hash_chain_data = await self._add_to_hash_chain(entry)
292
+
293
+ if not hash_chain_data:
294
+ raise RuntimeError(
295
+ f"Hash chain data not generated for action {action_type.value}. "
296
+ f"enable_hash_chain={self.enable_hash_chain}. "
297
+ f"This is a critical audit trail failure."
298
+ )
299
+
300
+ # Store in graph WITH hash chain data (signature + entry_hash)
301
+ await self._store_entry_in_graph(entry, action_type, hash_chain_data)
302
+
303
+ # Cache for quick access
304
+ self._cache_entry(entry)
305
+
306
+ # Queue for export if configured
307
+ if self.export_path:
308
+ self._export_buffer.append(entry)
309
+
310
+ # Return audit entry result with REQUIRED fields
311
+ return AuditEntryResult(
312
+ entry_id=entry.entry_id,
313
+ sequence_number=hash_chain_data["sequence_number"],
314
+ entry_hash=hash_chain_data["entry_hash"],
315
+ previous_hash=hash_chain_data.get("previous_hash"),
316
+ signature=hash_chain_data["signature"],
317
+ signing_key_id=hash_chain_data.get("signing_key_id"),
318
+ )
319
+
320
+ async def log_event(self, event_type: str, event_data: "EventPayload", **kwargs: object) -> AuditEntryResult:
321
+ """Log a general event.
322
+
323
+ Args:
324
+ event_type: Type of event being logged
325
+ event_data: Event data as EventPayload object
326
+
327
+ Returns:
328
+ AuditEntryResult with entry_id and hash chain data (if enabled)
329
+ """
330
+
331
+ # Convert EventPayload to AuditEventData
332
+ audit_data = AuditEventData(
333
+ entity_id=str(getattr(event_data, "user_id", "unknown")),
334
+ actor=str(getattr(event_data, "service_name", "system")),
335
+ outcome=str(getattr(event_data, "result", "success")),
336
+ severity="info",
337
+ action=str(getattr(event_data, "action", event_type)),
338
+ resource=str(getattr(event_data, "service_name", event_type)),
339
+ reason=str(getattr(event_data, "error", "event_logged") or "event_logged"),
340
+ metadata={},
341
+ )
342
+ try:
343
+ # Create audit entry with string-only details
344
+ details_dict = {}
345
+ for key, value in audit_data.model_dump().items():
346
+ if value is not None:
347
+ details_dict[key] = str(value) if not isinstance(value, str) else value
348
+
349
+ entry = AuditRequest(
350
+ entry_id=str(uuid4()),
351
+ timestamp=self._time_service.now() if self._time_service else datetime.now(),
352
+ entity_id=audit_data.entity_id,
353
+ event_type=event_type,
354
+ actor=audit_data.actor,
355
+ details=details_dict,
356
+ outcome=audit_data.outcome,
357
+ )
358
+
359
+ # Add to hash chain FIRST to get signature before storing in graph
360
+ logger.debug(f"enable_hash_chain={self.enable_hash_chain}")
361
+ hash_chain_data = None
362
+ if self.enable_hash_chain:
363
+ logger.debug("Adding entry to hash chain")
364
+ hash_chain_data = await self._add_to_hash_chain(entry)
365
+ else:
366
+ logger.debug("Hash chain disabled, not writing to audit_log table")
367
+
368
+ # Create graph node WITH signature from hash chain
369
+ node = AuditEntryNode(
370
+ id=f"audit_{entry.entry_id}",
371
+ action=event_type,
372
+ actor=entry.actor,
373
+ timestamp=entry.timestamp,
374
+ context=AuditEntryContext(
375
+ service_name=self.__class__.__name__,
376
+ correlation_id=entry.entry_id,
377
+ additional_data={
378
+ "event_type": event_type,
379
+ "severity": audit_data.severity,
380
+ "outcome": entry.outcome or "logged",
381
+ },
382
+ ),
383
+ signature=hash_chain_data.get("signature") if hash_chain_data else None,
384
+ hash_chain=hash_chain_data.get("entry_hash") if hash_chain_data else None,
385
+ scope=GraphScope.LOCAL,
386
+ attributes={},
387
+ )
388
+
389
+ # Store in graph with signature already set
390
+ if self._memory_bus:
391
+ await self._memory_bus.memorize(
392
+ node=node.to_graph_node(),
393
+ handler_name="audit_service",
394
+ metadata={"audit_entry": entry.model_dump(), "event": True, "immutable": True},
395
+ )
396
+
397
+ # Cache and export
398
+ self._cache_entry(entry)
399
+ if self.export_path:
400
+ logger.debug(f"Adding to export buffer, path={self.export_path}")
401
+ self._export_buffer.append(entry)
402
+ else:
403
+ logger.debug("No export path configured")
404
+
405
+ # Create trace correlation for this event
406
+ from ciris_engine.schemas.runtime.enums import HandlerActionType
407
+
408
+ # Extract action type from event data - try to map to HandlerActionType
409
+ # For non-handler events like WA operations, system events, etc., default to OBSERVE
410
+ action_name = event_data.action if hasattr(event_data, "action") else event_type
411
+ try:
412
+ action_type = HandlerActionType(action_name)
413
+ except ValueError:
414
+ # Not a handler action - use OBSERVE as default for system/auth events
415
+ action_type = HandlerActionType.OBSERVE
416
+
417
+ await self._create_trace_correlation(entry, action_type)
418
+
419
+ # Return full audit entry result with hash chain data
420
+ return AuditEntryResult(
421
+ entry_id=entry.entry_id,
422
+ sequence_number=hash_chain_data.get("sequence_number") if hash_chain_data else None,
423
+ entry_hash=hash_chain_data.get("entry_hash") if hash_chain_data else None,
424
+ previous_hash=hash_chain_data.get("previous_hash") if hash_chain_data else None,
425
+ signature=hash_chain_data.get("signature") if hash_chain_data else None,
426
+ signing_key_id=hash_chain_data.get("signing_key_id") if hash_chain_data else None,
427
+ )
428
+
429
+ except Exception as e:
430
+ logger.error(f"Failed to log event {event_type}: {e}")
431
+ # Fail fast - audit failures are critical
432
+ raise RuntimeError(f"Failed to create audit entry for event {event_type}: {e}") from e
433
+
434
+ async def log_conscience_event(
435
+ self, thought_id: str, decision: str, reasoning: str, metadata: Optional["EventPayload"] = None
436
+ ) -> None:
437
+ """Log conscience check events."""
438
+ # Create EventPayload for log_event
439
+ from ciris_engine.schemas.audit.core import EventPayload
440
+
441
+ # Use metadata if provided, otherwise create basic payload
442
+ if metadata:
443
+ event_payload = metadata
444
+ else:
445
+ event_payload = EventPayload(
446
+ action="conscience_check",
447
+ service_name="conscience_system",
448
+ user_id=thought_id,
449
+ result="allowed" if decision == "ALLOW" else "denied",
450
+ error=reasoning if decision != "ALLOW" else None,
451
+ )
452
+
453
+ await self.log_event("conscience_check", event_payload)
454
+
455
+ async def get_audit_trail(
456
+ self, entity_id: Optional[str] = None, hours: int = 24, action_types: Optional[List[str]] = None
457
+ ) -> List[AuditEntry]:
458
+ """Get audit trail for an entity."""
459
+ # Check cache first if entity_id provided
460
+ cached = []
461
+ if entity_id:
462
+ cached = [e for e in self._recent_entries if e.entity_id == entity_id]
463
+ else:
464
+ cached = list(self._recent_entries)
465
+
466
+ # Query from graph
467
+ if not self._memory_bus:
468
+ logger.error("Memory bus not available for audit queries")
469
+ # Convert cached AuditRequest to AuditEntry
470
+ return [self._audit_request_to_entry(e) for e in cached]
471
+
472
+ try:
473
+ # Query timeseries data
474
+ timeseries_data = await self._memory_bus.recall_timeseries(
475
+ scope="local", hours=hours, correlation_types=["AUDIT_EVENT"], handler_name="audit_service"
476
+ )
477
+
478
+ # Convert to AuditEntry objects and filter
479
+ results = self._convert_timeseries_to_entries(timeseries_data, entity_id)
480
+
481
+ # Combine with cache and deduplicate
482
+ # Convert AuditRequest to AuditEntry if needed
483
+ all_entries: Dict[str, AuditEntry] = {}
484
+ for req in cached:
485
+ if hasattr(req, "entry_id"):
486
+ entry = self._audit_request_to_entry(req)
487
+ all_entries[entry.id] = entry
488
+ for result_entry in results:
489
+ if hasattr(result_entry, "id"):
490
+ all_entries[result_entry.id] = result_entry
491
+ elif hasattr(result_entry, "entry_id"):
492
+ # This shouldn't happen but handle it anyway
493
+ entry = self._audit_request_to_entry(result_entry) # type: ignore
494
+ all_entries[entry.id] = entry
495
+
496
+ # Sort and limit
497
+ sorted_entries = sorted(all_entries.values(), key=lambda x: x.timestamp, reverse=True)
498
+
499
+ # Apply action_types filter if provided
500
+ if action_types:
501
+ sorted_entries = [e for e in sorted_entries if hasattr(e, "action") and e.action in action_types]
502
+
503
+ return sorted_entries
504
+
505
+ except Exception as e:
506
+ logger.error(f"Failed to get audit trail: {e}")
507
+ # Convert cached AuditRequest to AuditEntry
508
+ return [self._audit_request_to_entry(e) for e in cached]
509
+
510
+ async def query_audit_trail(self, query: AuditQuery) -> List[AuditEntry]:
511
+ """Query audit trail with advanced filters - implements AuditServiceProtocol."""
512
+ if not self._memory_bus:
513
+ return []
514
+
515
+ # Query audit_entry nodes directly from graph memory
516
+ from ciris_engine.schemas.services.graph_core import NodeType
517
+
518
+ # Search for all audit entries using query string format
519
+ # The search method looks for "type:" in the query string, not in filters
520
+ search_query = f"type:{NodeType.AUDIT_ENTRY.value} scope:{GraphScope.LOCAL.value}"
521
+
522
+ # Search for all audit entries
523
+ nodes = await self._memory_bus.search(search_query, filters=None, handler_name="audit_service")
524
+
525
+ # Convert GraphNode to AuditEntry
526
+ audit_entries = []
527
+ for node in nodes:
528
+ # Extract audit data from node attributes
529
+ if isinstance(node.attributes, dict):
530
+ attrs = node.attributes
531
+ elif hasattr(node.attributes, "model_dump"):
532
+ attrs = node.attributes.model_dump()
533
+ else:
534
+ continue
535
+
536
+ # Parse timestamp if it's a string
537
+ timestamp = attrs.get("timestamp", self._time_service.now() if self._time_service else datetime.now())
538
+ if isinstance(timestamp, str):
539
+ try:
540
+ timestamp = datetime.fromisoformat(timestamp.replace("Z", UTC_TIMEZONE_SUFFIX))
541
+ except (ValueError, TypeError):
542
+ timestamp = self._time_service.now() if self._time_service else datetime.now()
543
+
544
+ # Extract context data - handle both dict and nested structures
545
+ context_data = attrs.get("context", {})
546
+ if isinstance(context_data, dict):
547
+ # Extract service_name from nested structure or top level
548
+ service_name = context_data.get("service_name", attrs.get("service_name", ""))
549
+ correlation_id = context_data.get("correlation_id", attrs.get("correlation_id", ""))
550
+
551
+ # Get additional_data and flatten it to primitives only
552
+ additional_data = context_data.get("additional_data", {})
553
+ if isinstance(additional_data, dict):
554
+ # Filter out non-primitive values
555
+ flat_data: Dict[str, Union[str, int, float, bool]] = {}
556
+ for k, v in additional_data.items():
557
+ if isinstance(v, (str, int, float, bool)):
558
+ flat_data[k] = v
559
+ elif v is None:
560
+ # Skip None values
561
+ continue
562
+ else:
563
+ # Convert complex types to string
564
+ flat_data[k] = str(v)
565
+ additional_data = flat_data
566
+ else:
567
+ service_name = attrs.get("service_name", "")
568
+ correlation_id = attrs.get("correlation_id", "")
569
+ additional_data = {}
570
+
571
+ # Create AuditEntryNode from graph data
572
+ entry = AuditEntryNode(
573
+ id=node.id,
574
+ action=attrs.get("action", ""),
575
+ actor=attrs.get("actor", ""),
576
+ timestamp=timestamp,
577
+ context=AuditEntryContext(
578
+ service_name=service_name, correlation_id=correlation_id, additional_data=additional_data
579
+ ),
580
+ signature=attrs.get("signature"),
581
+ hash_chain=attrs.get("hash_chain"),
582
+ scope=node.scope,
583
+ attributes={},
584
+ )
585
+
586
+ # Apply filters from query
587
+ if query.start_time and entry.timestamp < query.start_time:
588
+ continue
589
+ if query.end_time and entry.timestamp > query.end_time:
590
+ continue
591
+ if query.actor and entry.actor != query.actor:
592
+ continue
593
+ if query.event_type and entry.action != query.event_type:
594
+ continue
595
+ if query.entity_id and entry.context.correlation_id != query.entity_id:
596
+ continue
597
+ if query.search_text:
598
+ # Simple text search in action and actor
599
+ search_lower = query.search_text.lower()
600
+ if search_lower not in entry.action.lower() and search_lower not in entry.actor.lower():
601
+ continue
602
+
603
+ audit_entries.append(entry)
604
+
605
+ # Sort and paginate
606
+ audit_entries.sort(key=lambda e: e.timestamp, reverse=query.order_desc)
607
+
608
+ # Apply offset and limit
609
+ start = query.offset
610
+ end = query.offset + query.limit if query.limit else None
611
+
612
+ return audit_entries[start:end]
613
+
614
+ async def verify_audit_integrity(self) -> VerificationReport:
615
+ """Verify the integrity of the audit trail."""
616
+ start_time = self._time_service.now() if self._time_service else datetime.now()
617
+
618
+ if not self.enable_hash_chain or not self.verifier:
619
+ return VerificationReport(
620
+ verified=False,
621
+ total_entries=0,
622
+ valid_entries=0,
623
+ invalid_entries=0,
624
+ chain_intact=False,
625
+ verification_started=start_time,
626
+ verification_completed=self._time_service.now() if self._time_service else datetime.now(),
627
+ duration_ms=0,
628
+ errors=["Hash chain not enabled"],
629
+ )
630
+
631
+ try:
632
+ result = await asyncio.to_thread(self.verifier.verify_complete_chain)
633
+ end_time = self._time_service.now() if self._time_service else datetime.now()
634
+
635
+ # Extract all errors
636
+ all_errors = []
637
+ all_errors.extend(result.hash_chain_errors or [])
638
+ all_errors.extend(result.signature_errors or [])
639
+ if result.error:
640
+ all_errors.append(result.error)
641
+
642
+ return VerificationReport(
643
+ verified=result.valid,
644
+ total_entries=result.entries_verified,
645
+ valid_entries=result.entries_verified if result.valid else 0,
646
+ invalid_entries=0 if result.valid else result.entries_verified,
647
+ chain_intact=result.hash_chain_valid,
648
+ last_valid_entry=None, # Not provided by CompleteVerificationResult
649
+ first_invalid_entry=None, # Not provided by CompleteVerificationResult
650
+ verification_started=start_time,
651
+ verification_completed=end_time,
652
+ duration_ms=(end_time - start_time).total_seconds() * 1000,
653
+ errors=all_errors,
654
+ warnings=[], # No warnings in CompleteVerificationResult
655
+ )
656
+ except Exception as e:
657
+ logger.error(f"Audit verification failed: {e}")
658
+ end_time = self._time_service.now() if self._time_service else datetime.now()
659
+ return VerificationReport(
660
+ verified=False,
661
+ total_entries=0,
662
+ valid_entries=0,
663
+ invalid_entries=0,
664
+ chain_intact=False,
665
+ verification_started=start_time,
666
+ verification_completed=end_time,
667
+ duration_ms=(end_time - start_time).total_seconds() * 1000,
668
+ errors=[str(e)],
669
+ )
670
+
671
+ async def get_verification_report(self) -> VerificationReport:
672
+ """Generate a comprehensive audit verification report."""
673
+ start_time = self._time_service.now() if self._time_service else datetime.now()
674
+
675
+ if not self.enable_hash_chain or not self.verifier:
676
+ return VerificationReport(
677
+ verified=False,
678
+ total_entries=0,
679
+ valid_entries=0,
680
+ invalid_entries=0,
681
+ chain_intact=False,
682
+ verification_started=start_time,
683
+ verification_completed=self._time_service.now() if self._time_service else datetime.now(),
684
+ duration_ms=0,
685
+ errors=["Hash chain not enabled"],
686
+ )
687
+
688
+ try:
689
+ # Delegate to verify_audit_integrity which already returns VerificationReport
690
+ return await self.verify_audit_integrity()
691
+ except Exception as e:
692
+ logger.error(f"Failed to generate verification report: {e}")
693
+ end_time = self._time_service.now() if self._time_service else datetime.now()
694
+ return VerificationReport(
695
+ verified=False,
696
+ total_entries=0,
697
+ valid_entries=0,
698
+ invalid_entries=0,
699
+ chain_intact=False,
700
+ verification_started=start_time,
701
+ verification_completed=end_time,
702
+ duration_ms=(end_time - start_time).total_seconds() * 1000,
703
+ errors=[str(e)],
704
+ )
705
+
706
+ async def export_audit_data(
707
+ self, start_time: Optional[datetime] = None, end_time: Optional[datetime] = None, format: Optional[str] = None
708
+ ) -> str:
709
+ """Export audit data to file."""
710
+ format = format or self.export_format
711
+
712
+ # Query data
713
+ from ciris_engine.schemas.services.graph.audit import AuditQuery
714
+
715
+ query = AuditQuery(start_time=start_time, end_time=end_time, limit=10000) # Higher limit for exports
716
+ entries = await self.query_audit_trail(query)
717
+
718
+ # Generate filename
719
+ timestamp = (self._time_service.now() if self._time_service else datetime.now()).strftime("%Y%m%d_%H%M%S")
720
+ if not self.export_path:
721
+ raise ValueError("Export path not configured")
722
+ filename = self.export_path.parent / f"audit_export_{timestamp}.{format}"
723
+
724
+ # Convert AuditEntry to AuditRequest for export methods
725
+ audit_requests = []
726
+ for entry in entries:
727
+ audit_requests.append(
728
+ AuditRequest(
729
+ entry_id=entry.id,
730
+ timestamp=entry.timestamp,
731
+ entity_id=entry.context.correlation_id or entry.actor,
732
+ event_type=entry.action,
733
+ actor=entry.actor,
734
+ details={
735
+ "service": entry.context.service_name or "",
736
+ "method": entry.context.method_name or "",
737
+ "user_id": entry.context.user_id or "",
738
+ **(
739
+ {k: str(v) for k, v in entry.context.additional_data.items()}
740
+ if entry.context.additional_data
741
+ else {}
742
+ ),
743
+ },
744
+ outcome=None, # AuditEntry doesn't have outcome field
745
+ )
746
+ )
747
+
748
+ # Export based on format
749
+ if format == "jsonl":
750
+ await self._export_jsonl(audit_requests, filename)
751
+ elif format == "csv":
752
+ await self._export_csv(audit_requests, filename)
753
+ elif format == "sqlite":
754
+ await self._export_sqlite(audit_requests, filename)
755
+ else:
756
+ raise ValueError(f"Unsupported export format: {format}")
757
+
758
+ return str(filename)
759
+
760
+ # ========== GraphServiceProtocol Implementation ==========
761
+
762
+ def get_node_type(self) -> str:
763
+ """Get the type of nodes this service manages."""
764
+ return "AUDIT"
765
+
766
+ # ========== ServiceProtocol Implementation ==========
767
+
768
+ def _collect_custom_metrics(self) -> Dict[str, float]:
769
+ """Collect audit-specific metrics."""
770
+ metrics = super()._collect_custom_metrics()
771
+
772
+ # Calculate cache size
773
+ cache_size_mb = 0.0
774
+ try:
775
+ cache_size = sys.getsizeof(self._recent_entries) + sys.getsizeof(self._export_buffer)
776
+ cache_size_mb = cache_size / 1024 / 1024
777
+ except Exception:
778
+ pass
779
+
780
+ # Add audit-specific metrics
781
+ metrics.update(
782
+ {
783
+ "cached_entries": float(len(self._recent_entries)),
784
+ "pending_exports": float(len(self._export_buffer)),
785
+ "hash_chain_enabled": float(self.enable_hash_chain),
786
+ "cache_size_mb": cache_size_mb,
787
+ }
788
+ )
789
+
790
+ return metrics
791
+
792
+ async def get_metrics(self) -> Dict[str, float]:
793
+ """
794
+ Get all audit service metrics including base, custom, and v1.4.3 specific.
795
+ """
796
+ # Get all base + custom metrics
797
+ metrics = self._collect_metrics()
798
+ # Count total events from cache and estimate from graph
799
+ total_events = len(self._recent_entries)
800
+
801
+ # Count events by severity from cached entries
802
+ severity_counts = {"info": 0, "low": 0, "medium": 0, "high": 0, "critical": 0}
803
+ compliance_checks = 0
804
+
805
+ # Analyze cached entries for severity and compliance
806
+ for entry in self._recent_entries:
807
+ # Extract severity from details or determine from event type
808
+ details = entry.details or {}
809
+ severity = details.get("severity", "info")
810
+
811
+ # Count by severity
812
+ if severity in severity_counts:
813
+ severity_counts[severity] += 1
814
+ else:
815
+ severity_counts["info"] += 1
816
+
817
+ # Count compliance-related events
818
+ event_type = entry.event_type.lower()
819
+ if any(keyword in event_type for keyword in ["compliance", "audit", "verify", "check", "integrity"]):
820
+ compliance_checks += 1
821
+
822
+ # Calculate uptime
823
+ uptime_seconds = 0.0
824
+ if self._start_time:
825
+ current_time = self._time_service.now() if self._time_service else datetime.now()
826
+ uptime_seconds = (current_time - self._start_time).total_seconds()
827
+
828
+ # Return exact metrics from v1.4.3 set
829
+ # Add v1.4.3 specific metrics
830
+ metrics.update(
831
+ {
832
+ "audit_events_total": float(total_events),
833
+ "audit_events_by_severity": float(sum(severity_counts.values())), # Flattened count
834
+ "audit_compliance_checks": float(compliance_checks),
835
+ "audit_uptime_seconds": uptime_seconds,
836
+ }
837
+ )
838
+
839
+ return metrics
840
+
841
+ # ========== Private Helper Methods ==========
842
+
843
+ async def _store_entry_in_graph(
844
+ self, entry: AuditRequest, action_type: HandlerActionType, hash_chain_data: Optional[JSONDict] = None
845
+ ) -> None:
846
+ """Store an audit entry in the graph and create a trace correlation.
847
+
848
+ Args:
849
+ entry: The audit request to store
850
+ action_type: The handler action type
851
+ hash_chain_data: Optional hash chain data with signature/entry_hash to include in node
852
+ """
853
+ if not self._memory_bus:
854
+ logger.error("Memory bus not available for audit storage")
855
+ return
856
+
857
+ # Create specialized audit node WITH signature from hash chain
858
+ # Build additional_data with core fields plus any extra parameters from context
859
+ import json
860
+
861
+ additional_data = {
862
+ "thought_id": entry.details.get("thought_id", ""),
863
+ "task_id": entry.details.get("task_id", ""),
864
+ "outcome": entry.outcome or "success",
865
+ "severity": self._get_severity(action_type),
866
+ }
867
+
868
+ # Include any additional parameters from the audit context (e.g., tool_name, follow_up_thought_id)
869
+ logger.debug(f"entry.details keys: {entry.details.keys()}")
870
+ if "parameters" in entry.details and entry.details["parameters"]:
871
+ logger.debug(f"Found parameters in entry.details: {entry.details['parameters']}")
872
+ try:
873
+ # Deserialize JSON string back to dict
874
+ params_dict = json.loads(entry.details["parameters"])
875
+ additional_data.update(params_dict)
876
+ logger.debug(f"Updated additional_data: {additional_data}")
877
+ except json.JSONDecodeError as e:
878
+ logger.warning(f"Failed to parse parameters JSON: {e}")
879
+ else:
880
+ logger.debug("No 'parameters' key in entry.details or empty")
881
+
882
+ node = AuditEntryNode(
883
+ id=f"audit_{action_type.value}_{entry.entry_id}",
884
+ action=action_type.value,
885
+ actor=entry.actor,
886
+ timestamp=entry.timestamp,
887
+ context=AuditEntryContext(
888
+ service_name=entry.details.get("handler_name", ""),
889
+ correlation_id=entry.entry_id,
890
+ additional_data=additional_data,
891
+ ),
892
+ signature=hash_chain_data.get("signature") if hash_chain_data else None,
893
+ hash_chain=hash_chain_data.get("entry_hash") if hash_chain_data else None,
894
+ scope=GraphScope.LOCAL,
895
+ attributes={"action_type": action_type.value, "event_id": entry.entry_id},
896
+ )
897
+
898
+ # Store via memory bus with signature already set
899
+ result = await self._memory_bus.memorize(
900
+ node=node.to_graph_node(),
901
+ handler_name="audit_service",
902
+ metadata={"audit_entry": entry.model_dump(), "immutable": True},
903
+ )
904
+
905
+ if result.status != MemoryOpStatus.OK:
906
+ logger.error(f"Failed to store audit entry in graph: {result}")
907
+
908
+ # Create a ServiceCorrelation for trace tracking
909
+ await self._create_trace_correlation(entry, action_type)
910
+
911
+ async def _create_trace_correlation(self, entry: AuditRequest, action_type: HandlerActionType) -> None:
912
+ """Create a ServiceCorrelation for trace tracking."""
913
+ logger.debug(f"Creating trace correlation for audit event {entry.entry_id}")
914
+ try:
915
+ from ciris_engine.schemas.telemetry.core import (
916
+ CorrelationType,
917
+ ServiceCorrelation,
918
+ ServiceCorrelationStatus,
919
+ ServiceRequestData,
920
+ ServiceResponseData,
921
+ TraceContext,
922
+ )
923
+
924
+ # Get telemetry service from runtime
925
+ telemetry_service = None
926
+ if hasattr(self, "_runtime") and self._runtime:
927
+ telemetry_service = getattr(self._runtime, "telemetry_service", None)
928
+
929
+ if not telemetry_service:
930
+ # Try to get from service registry
931
+ if self._service_registry:
932
+ from ciris_engine.schemas.runtime.enums import ServiceType
933
+
934
+ services = self._service_registry.get_services_by_type(ServiceType.TELEMETRY)
935
+ telemetry_service = services[0] if services else None
936
+
937
+ if not telemetry_service:
938
+ logger.debug("Telemetry service not available for trace correlation")
939
+ return
940
+
941
+ # Create correlation
942
+ correlation = ServiceCorrelation(
943
+ correlation_id=entry.entry_id,
944
+ correlation_type=CorrelationType.AUDIT_EVENT,
945
+ service_type="audit",
946
+ handler_name=entry.actor,
947
+ action_type=action_type.value,
948
+ request_data=ServiceRequestData(
949
+ service_type="audit",
950
+ method_name="log_event",
951
+ thought_id=entry.details.get("thought_id"),
952
+ task_id=entry.details.get("task_id"),
953
+ parameters={
954
+ "action": action_type.value,
955
+ "entity_id": entry.entity_id,
956
+ },
957
+ request_timestamp=entry.timestamp,
958
+ ),
959
+ response_data=ServiceResponseData(
960
+ success=True if entry.outcome == "success" else False,
961
+ execution_time_ms=0, # We don't track this for audit events
962
+ response_timestamp=entry.timestamp, # Use same timestamp for audit events
963
+ ),
964
+ status=ServiceCorrelationStatus.COMPLETED,
965
+ created_at=entry.timestamp,
966
+ updated_at=entry.timestamp,
967
+ timestamp=entry.timestamp,
968
+ trace_context=TraceContext(
969
+ trace_id=f"trace_{entry.entry_id}",
970
+ span_id=entry.entry_id,
971
+ parent_span_id=entry.details.get("thought_id"),
972
+ span_name=f"audit.{action_type.value}",
973
+ ),
974
+ tags={
975
+ "action": action_type.value,
976
+ "actor": entry.actor,
977
+ "severity": self._get_severity(action_type),
978
+ },
979
+ )
980
+
981
+ # Store correlation in telemetry service
982
+ if hasattr(telemetry_service, "_store_correlation"):
983
+ await telemetry_service._store_correlation(correlation)
984
+ logger.debug(f"Successfully stored trace correlation for audit event {entry.entry_id}")
985
+ else:
986
+ logger.warning(f"Telemetry service does not have _store_correlation method")
987
+
988
+ except Exception as e:
989
+ logger.error(f"Failed to create trace correlation: {e}", exc_info=True)
990
+ # Don't fail the audit operation if trace creation fails
991
+
992
+ async def _initialize_hash_chain(self) -> None:
993
+ """Initialize hash chain components."""
994
+ try:
995
+ # Ensure directories exist
996
+ self.key_path.mkdir(parents=True, exist_ok=True)
997
+
998
+ # Initialize database
999
+ await self._init_database()
1000
+
1001
+ # Initialize components
1002
+ self.hash_chain = AuditHashChain(str(self.db_path))
1003
+ logger.debug(
1004
+ f"Initializing AuditSignatureManager with key_path={self.key_path}, db_path={self.db_path}, time_service={self._time_service}"
1005
+ )
1006
+
1007
+ # Ensure time_service is not None
1008
+ if not self._time_service:
1009
+ raise RuntimeError("TimeService is None - cannot initialize AuditSignatureManager")
1010
+
1011
+ # Check actual types
1012
+ logger.debug(
1013
+ f"Types: key_path={type(self.key_path)}, db_path={type(self.db_path)}, time_service={type(self._time_service)}"
1014
+ )
1015
+
1016
+ self.signature_manager = AuditSignatureManager(str(self.key_path), str(self.db_path), self._time_service)
1017
+ self.verifier = AuditVerifier(str(self.db_path), str(self.key_path), self._time_service)
1018
+
1019
+ # Initialize in thread
1020
+ await asyncio.to_thread(self._init_components_sync)
1021
+
1022
+ logger.info("Hash chain audit system initialized")
1023
+
1024
+ except Exception as e:
1025
+ logger.error(f"CRITICAL: Failed to initialize hash chain: {e}", exc_info=True)
1026
+ # Hash chain is REQUIRED for audit integrity - do not allow fallback
1027
+ raise RuntimeError(f"Audit hash chain initialization failed: {e}") from e
1028
+
1029
+ def _init_components_sync(self) -> None:
1030
+ """Synchronous initialization of audit components."""
1031
+ if not self.hash_chain or not self.signature_manager or not self.verifier:
1032
+ raise RuntimeError("Hash chain components not initialized")
1033
+
1034
+ self.hash_chain.initialize()
1035
+ self.signature_manager.initialize()
1036
+ self.verifier.initialize()
1037
+
1038
+ if not self.signature_manager.test_signing():
1039
+ raise RuntimeError("Signing test failed")
1040
+
1041
+ async def _init_database(self) -> None:
1042
+ """Initialize the audit database."""
1043
+
1044
+ def _create_tables() -> None:
1045
+ conn = sqlite3.connect(str(self.db_path), check_same_thread=False)
1046
+ cursor = conn.cursor()
1047
+
1048
+ # Set PRAGMA statements for stability and corruption prevention
1049
+ cursor.execute(PRAGMA_JOURNAL_MODE_WAL)
1050
+ cursor.execute(PRAGMA_BUSY_TIMEOUT_5000)
1051
+ cursor.execute(PRAGMA_SYNCHRONOUS_NORMAL)
1052
+ cursor.execute("PRAGMA foreign_keys=ON")
1053
+
1054
+ # Check database integrity
1055
+ integrity_result = cursor.execute("PRAGMA integrity_check").fetchone()
1056
+ if integrity_result[0] != "ok":
1057
+ logger.error(f"Audit database integrity check failed: {integrity_result}")
1058
+ # Close and recreate the database
1059
+ conn.close()
1060
+ import os
1061
+
1062
+ db_path_str = str(self.db_path)
1063
+ # Remove corrupted database and WAL/SHM files
1064
+ for ext in ["", "-wal", "-shm"]:
1065
+ try:
1066
+ os.remove(db_path_str + ext)
1067
+ except OSError:
1068
+ pass
1069
+ logger.warning("Corrupted audit database removed, recreating...")
1070
+ conn = sqlite3.connect(db_path_str, check_same_thread=False)
1071
+ cursor = conn.cursor()
1072
+ cursor.execute(PRAGMA_JOURNAL_MODE_WAL)
1073
+ cursor.execute(PRAGMA_BUSY_TIMEOUT_5000)
1074
+ cursor.execute(PRAGMA_SYNCHRONOUS_NORMAL)
1075
+
1076
+ # Audit log table
1077
+ cursor.execute(
1078
+ """
1079
+ CREATE TABLE IF NOT EXISTS audit_log (
1080
+ entry_id INTEGER PRIMARY KEY AUTOINCREMENT,
1081
+ event_id TEXT NOT NULL UNIQUE,
1082
+ event_timestamp TEXT NOT NULL,
1083
+ event_type TEXT NOT NULL,
1084
+ originator_id TEXT NOT NULL,
1085
+ target_id TEXT,
1086
+ event_summary TEXT,
1087
+ event_payload TEXT,
1088
+ sequence_number INTEGER NOT NULL,
1089
+ previous_hash TEXT NOT NULL,
1090
+ entry_hash TEXT NOT NULL,
1091
+ signature TEXT NOT NULL,
1092
+ signing_key_id TEXT NOT NULL,
1093
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
1094
+ UNIQUE(sequence_number)
1095
+ )
1096
+ """
1097
+ )
1098
+
1099
+ # Signing keys table
1100
+ cursor.execute(
1101
+ """
1102
+ CREATE TABLE IF NOT EXISTS audit_signing_keys (
1103
+ key_id TEXT PRIMARY KEY,
1104
+ public_key TEXT NOT NULL,
1105
+ algorithm TEXT NOT NULL DEFAULT 'rsa-pss',
1106
+ key_size INTEGER NOT NULL DEFAULT 2048,
1107
+ created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
1108
+ revoked_at TEXT
1109
+ )
1110
+ """
1111
+ )
1112
+
1113
+ # Indexes
1114
+ cursor.execute(
1115
+ """
1116
+ CREATE INDEX IF NOT EXISTS idx_audit_log_event_timestamp
1117
+ ON audit_log(event_timestamp)
1118
+ """
1119
+ )
1120
+
1121
+ cursor.execute(
1122
+ """
1123
+ CREATE INDEX IF NOT EXISTS idx_audit_log_event_type
1124
+ ON audit_log(event_type)
1125
+ """
1126
+ )
1127
+
1128
+ conn.commit()
1129
+ conn.close()
1130
+
1131
+ await asyncio.to_thread(_create_tables)
1132
+ self._db_connection = sqlite3.connect(str(self.db_path), check_same_thread=False)
1133
+ # Apply PRAGMA settings to persistent connection
1134
+ self._db_connection.execute(PRAGMA_JOURNAL_MODE_WAL)
1135
+ self._db_connection.execute(PRAGMA_BUSY_TIMEOUT_5000)
1136
+ self._db_connection.execute(PRAGMA_SYNCHRONOUS_NORMAL)
1137
+
1138
+ async def _add_to_hash_chain(self, entry: AuditRequest) -> Optional[JSONDict]:
1139
+ """Add an entry to the hash chain.
1140
+
1141
+ Returns:
1142
+ Dict with hash chain data (sequence_number, entry_hash, previous_hash, signature, signing_key_id)
1143
+ or None if hash chain is disabled
1144
+ """
1145
+ if not self.enable_hash_chain:
1146
+ return None
1147
+
1148
+ async with self._hash_chain_lock:
1149
+ hash_chain_data: Optional[JSONDict] = None
1150
+
1151
+ def _write_to_chain() -> JSONDict:
1152
+ entry_dict: JSONDict = {
1153
+ "event_id": entry.entry_id,
1154
+ "event_timestamp": entry.timestamp.isoformat(),
1155
+ "event_type": entry.event_type,
1156
+ "originator_id": entry.entity_id,
1157
+ "event_payload": json.dumps(entry.details),
1158
+ }
1159
+
1160
+ if not self.hash_chain or not self.signature_manager:
1161
+ raise RuntimeError("Hash chain not available")
1162
+
1163
+ prepared = self.hash_chain.prepare_entry(entry_dict)
1164
+ entry_hash_val = get_str(prepared, "entry_hash", "")
1165
+ signature = self.signature_manager.sign_entry(entry_hash_val)
1166
+
1167
+ if not self._db_connection:
1168
+ raise RuntimeError("Database connection not available")
1169
+
1170
+ cursor = self._db_connection.cursor()
1171
+ cursor.execute(
1172
+ """
1173
+ INSERT INTO audit_log
1174
+ (event_id, event_timestamp, event_type, originator_id,
1175
+ event_summary, event_payload, sequence_number, previous_hash,
1176
+ entry_hash, signature, signing_key_id)
1177
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1178
+ """,
1179
+ (
1180
+ entry.entry_id,
1181
+ entry.timestamp.isoformat(),
1182
+ entry.event_type,
1183
+ entry.entity_id,
1184
+ f"{entry.event_type} by {entry.actor}",
1185
+ json.dumps(entry.details),
1186
+ prepared["sequence_number"],
1187
+ prepared["previous_hash"],
1188
+ prepared["entry_hash"],
1189
+ signature,
1190
+ self.signature_manager.key_id or "unknown",
1191
+ ),
1192
+ )
1193
+
1194
+ self._db_connection.commit()
1195
+
1196
+ # Return hash chain data
1197
+ result_dict: JSONDict = {
1198
+ "sequence_number": get_int(prepared, "sequence_number", 0),
1199
+ "entry_hash": entry_hash_val,
1200
+ "previous_hash": get_str(prepared, "previous_hash", ""),
1201
+ "signature": signature,
1202
+ "signing_key_id": self.signature_manager.key_id or "unknown",
1203
+ }
1204
+ return result_dict
1205
+
1206
+ try:
1207
+ logger.debug(f"About to write to hash chain for entry {entry.entry_id}")
1208
+ hash_chain_data = await asyncio.to_thread(_write_to_chain)
1209
+ logger.debug(f"Successfully wrote to hash chain for entry {entry.entry_id}")
1210
+ return hash_chain_data
1211
+ except Exception as e:
1212
+ logger.error(f"Failed to add to hash chain: {e}", exc_info=True)
1213
+ return None
1214
+
1215
+ def _cache_entry(self, entry: AuditRequest) -> None:
1216
+ """Add entry to cache."""
1217
+ self._recent_entries.append(entry)
1218
+ if len(self._recent_entries) > self._max_cached_entries:
1219
+ self._recent_entries = self._recent_entries[-self._max_cached_entries :]
1220
+
1221
+ async def _export_worker(self) -> None:
1222
+ """Background task to export audit data."""
1223
+ while True:
1224
+ try:
1225
+ await asyncio.sleep(60) # Export every minute
1226
+ if self._export_buffer:
1227
+ await self._flush_exports()
1228
+ except asyncio.CancelledError:
1229
+ logger.debug("Export worker cancelled")
1230
+ raise # Re-raise to properly exit the task
1231
+ except Exception as e:
1232
+ logger.error(f"Export worker error: {e}")
1233
+
1234
+ async def _flush_exports(self) -> None:
1235
+ """Flush export buffer to file."""
1236
+ if not self._export_buffer or not self.export_path:
1237
+ return
1238
+
1239
+ try:
1240
+ if self.export_format == "jsonl":
1241
+ await self._export_jsonl(self._export_buffer, self.export_path)
1242
+ elif self.export_format == "csv":
1243
+ await self._export_csv(self._export_buffer, self.export_path)
1244
+ elif self.export_format == "sqlite":
1245
+ await self._export_sqlite(self._export_buffer, self.export_path)
1246
+
1247
+ self._export_buffer.clear()
1248
+ except Exception as e:
1249
+ logger.error(f"Failed to flush exports: {e}")
1250
+
1251
+ async def _export_jsonl(self, entries: List[AuditRequest], path: Path) -> None:
1252
+ """Export entries to JSONL format."""
1253
+
1254
+ def _write_jsonl() -> None:
1255
+ with open(path, "a") as f:
1256
+ for entry in entries:
1257
+ f.write(json.dumps(entry.model_dump(), default=str) + "\n")
1258
+
1259
+ await asyncio.to_thread(_write_jsonl)
1260
+
1261
+ async def _export_csv(self, entries: List[AuditRequest], path: Path) -> None:
1262
+ """Export entries to CSV format."""
1263
+ import csv
1264
+
1265
+ def _write_csv() -> None:
1266
+ file_exists = path.exists()
1267
+ with open(path, "a", newline="") as f:
1268
+ writer = csv.writer(f)
1269
+
1270
+ # Write header if new file
1271
+ if not file_exists:
1272
+ writer.writerow(["entry_id", "timestamp", "entity_id", "event_type", "actor", "outcome", "details"])
1273
+
1274
+ # Write entries
1275
+ for entry in entries:
1276
+ writer.writerow(
1277
+ [
1278
+ entry.entry_id,
1279
+ entry.timestamp.isoformat(),
1280
+ entry.entity_id,
1281
+ entry.event_type,
1282
+ entry.actor,
1283
+ entry.outcome,
1284
+ json.dumps(entry.details),
1285
+ ]
1286
+ )
1287
+
1288
+ await asyncio.to_thread(_write_csv)
1289
+
1290
+ async def _export_sqlite(self, entries: List[AuditRequest], path: Path) -> None:
1291
+ """Export entries to SQLite format."""
1292
+
1293
+ def _write_sqlite() -> None:
1294
+ conn = sqlite3.connect(str(path), check_same_thread=False)
1295
+ cursor = conn.cursor()
1296
+
1297
+ # Create table if needed
1298
+ cursor.execute(
1299
+ """
1300
+ CREATE TABLE IF NOT EXISTS audit_export (
1301
+ entry_id TEXT PRIMARY KEY,
1302
+ timestamp TEXT NOT NULL,
1303
+ entity_id TEXT NOT NULL,
1304
+ event_type TEXT NOT NULL,
1305
+ actor TEXT NOT NULL,
1306
+ outcome TEXT,
1307
+ details TEXT
1308
+ )
1309
+ """
1310
+ )
1311
+
1312
+ # Use dialect-aware query builder for UPSERT
1313
+ adapter = get_adapter()
1314
+ builder = adapter.get_query_builder()
1315
+
1316
+ query = builder.insert(
1317
+ table="audit_export",
1318
+ columns=["entry_id", "timestamp", "entity_id", "event_type", "actor", "outcome", "details"],
1319
+ conflict_resolution=ConflictResolution.REPLACE,
1320
+ conflict_columns=["entry_id"],
1321
+ )
1322
+ sql = query.to_sql(adapter)
1323
+
1324
+ # Insert entries
1325
+ for entry in entries:
1326
+ cursor.execute(
1327
+ sql,
1328
+ (
1329
+ entry.entry_id,
1330
+ entry.timestamp.isoformat(),
1331
+ entry.entity_id,
1332
+ entry.event_type,
1333
+ entry.actor,
1334
+ entry.outcome,
1335
+ json.dumps(entry.details),
1336
+ ),
1337
+ )
1338
+
1339
+ conn.commit()
1340
+ conn.close()
1341
+
1342
+ await asyncio.to_thread(_write_sqlite)
1343
+
1344
+ def _get_severity(self, action: HandlerActionType) -> str:
1345
+ """Determine severity level for an action."""
1346
+ if action in [HandlerActionType.DEFER, HandlerActionType.REJECT, HandlerActionType.FORGET]:
1347
+ return "high"
1348
+ elif action in [HandlerActionType.TOOL, HandlerActionType.MEMORIZE, HandlerActionType.TASK_COMPLETE]:
1349
+ return "medium"
1350
+ else:
1351
+ return "low"
1352
+
1353
+ def _calculate_hours(self, start_time: Optional[datetime], end_time: Optional[datetime]) -> int:
1354
+ """Calculate hours for time range."""
1355
+ if start_time and end_time:
1356
+ return int((end_time - start_time).total_seconds() / 3600)
1357
+ elif start_time:
1358
+ return int(
1359
+ ((self._time_service.now() if self._time_service else datetime.now()) - start_time).total_seconds()
1360
+ / 3600
1361
+ )
1362
+ else:
1363
+ return 24 * 30 # Default 30 days
1364
+
1365
+ def _matches_filters(
1366
+ self,
1367
+ data: GraphNode,
1368
+ start_time: Optional[datetime],
1369
+ end_time: Optional[datetime],
1370
+ action_types: Optional[List[str]],
1371
+ thought_id: Optional[str],
1372
+ task_id: Optional[str],
1373
+ ) -> bool:
1374
+ """Check if data matches query filters."""
1375
+ # Time filters
1376
+ timestamp = data.attributes.created_at if hasattr(data.attributes, "created_at") else data.updated_at
1377
+ if timestamp:
1378
+ if start_time and timestamp < start_time:
1379
+ return False
1380
+ if end_time and timestamp > end_time:
1381
+ return False
1382
+
1383
+ # Action type filter
1384
+ tags = data.attributes.tags if hasattr(data.attributes, "tags") else []
1385
+ _tag_dict = dict.fromkeys(tags, True) # Convert list to dict for lookup
1386
+
1387
+ # Check attributes dict as well
1388
+ attrs = data.attributes.model_dump() if hasattr(data.attributes, "model_dump") else {}
1389
+
1390
+ if action_types and attrs.get("action_type") not in action_types:
1391
+ return False
1392
+
1393
+ # Entity filters
1394
+ if thought_id and attrs.get("thought_id") != thought_id:
1395
+ return False
1396
+ if task_id and attrs.get("task_id") != task_id:
1397
+ return False
1398
+
1399
+ return True
1400
+
1401
+ def _extract_thought_id_from_audit_node(self, audit_node: AuditEntryNode) -> str:
1402
+ """Extract thought_id from audit node context."""
1403
+ if not audit_node.context.additional_data:
1404
+ return ""
1405
+ value = audit_node.context.additional_data.get("thought_id", "")
1406
+ return str(value) if value else ""
1407
+
1408
+ def _extract_task_id_from_audit_node(self, audit_node: AuditEntryNode) -> str:
1409
+ """Extract task_id from audit node context."""
1410
+ if not audit_node.context.additional_data:
1411
+ return ""
1412
+ value = audit_node.context.additional_data.get("task_id", "")
1413
+ return str(value) if value else ""
1414
+
1415
+ def _extract_outcome_from_audit_node(self, audit_node: AuditEntryNode) -> Optional[str]:
1416
+ """Extract outcome from audit node context."""
1417
+ if not audit_node.context.additional_data:
1418
+ return None
1419
+ value = audit_node.context.additional_data.get("outcome")
1420
+ return str(value) if value is not None else None
1421
+
1422
+ def _convert_audit_entry_node(self, audit_node: AuditEntryNode) -> AuditRequest:
1423
+ """Convert AuditEntryNode to AuditRequest."""
1424
+ return AuditRequest(
1425
+ entry_id=audit_node.id.replace("audit_", ""),
1426
+ timestamp=audit_node.timestamp,
1427
+ entity_id=audit_node.context.correlation_id or "",
1428
+ event_type=audit_node.action,
1429
+ actor=audit_node.actor,
1430
+ details={
1431
+ "action_type": audit_node.action,
1432
+ "thought_id": self._extract_thought_id_from_audit_node(audit_node),
1433
+ "task_id": self._extract_task_id_from_audit_node(audit_node),
1434
+ "handler_name": audit_node.context.service_name or "",
1435
+ "context": audit_node.context.model_dump(),
1436
+ },
1437
+ outcome=self._extract_outcome_from_audit_node(audit_node),
1438
+ )
1439
+
1440
+ def _get_timestamp_from_data(self, data: GraphNode) -> datetime:
1441
+ """Get timestamp from data node with fallback."""
1442
+ timestamp = data.attributes.created_at if hasattr(data.attributes, "created_at") else data.updated_at
1443
+ if not timestamp:
1444
+ timestamp = self._time_service.now() if self._time_service else datetime.now()
1445
+ return timestamp
1446
+
1447
+ def _extract_action_type_from_attrs(self, attrs: JSONDict) -> Optional[str]:
1448
+ """Extract action_type from attributes with fallback."""
1449
+ action_type_val = get_str(attrs, "action_type", "")
1450
+ if action_type_val:
1451
+ return action_type_val
1452
+ return None
1453
+
1454
+ def _create_audit_request_from_attrs(self, attrs: JSONDict, timestamp: datetime, action_type: str) -> AuditRequest:
1455
+ """Create AuditRequest from manual attribute parsing."""
1456
+ return AuditRequest(
1457
+ entry_id=attrs.get("event_id", str(uuid4())),
1458
+ timestamp=timestamp,
1459
+ entity_id=attrs.get("thought_id", "") or attrs.get("task_id", ""),
1460
+ event_type=action_type,
1461
+ actor=attrs.get("actor", attrs.get("handler_name", "system")),
1462
+ details={
1463
+ "action_type": action_type,
1464
+ "thought_id": attrs.get("thought_id", ""),
1465
+ "task_id": attrs.get("task_id", ""),
1466
+ "handler_name": attrs.get("handler_name", ""),
1467
+ "attributes": attrs,
1468
+ },
1469
+ outcome=attrs.get("outcome"),
1470
+ )
1471
+
1472
+ def _tsdb_to_audit_entry(self, data: GraphNode) -> Optional[AuditRequest]:
1473
+ """Convert TSDB node to AuditEntry."""
1474
+ # Check if this is an AuditEntryNode by looking for the marker
1475
+ attrs = data.attributes if isinstance(data.attributes, dict) else {}
1476
+
1477
+ # If it's an AuditEntryNode stored with to_graph_node(), convert back
1478
+ if attrs.get("node_class") == "AuditEntry":
1479
+ try:
1480
+ audit_node = AuditEntryNode.from_graph_node(data)
1481
+ return self._convert_audit_entry_node(audit_node)
1482
+ except Exception as e:
1483
+ logger.warning(f"Failed to convert AuditEntryNode: {e}, falling back to manual parsing")
1484
+
1485
+ # Fallback: manual parsing for backwards compatibility
1486
+ attrs = data.attributes.model_dump() if hasattr(data.attributes, "model_dump") else {}
1487
+
1488
+ action_type = self._extract_action_type_from_attrs(attrs)
1489
+ if not action_type:
1490
+ return None
1491
+
1492
+ timestamp = self._get_timestamp_from_data(data)
1493
+ return self._create_audit_request_from_attrs(attrs, timestamp, action_type)
1494
+
1495
+ def _convert_timeseries_to_entries(
1496
+ self, timeseries_data: List[TimeSeriesDataPoint], entity_id: Optional[str] = None
1497
+ ) -> List[AuditEntry]:
1498
+ """Convert timeseries data to audit entries."""
1499
+ results: List[AuditEntry] = []
1500
+
1501
+ for data in timeseries_data:
1502
+ # Filter by entity if specified
1503
+ if entity_id:
1504
+ tags = data.tags or {}
1505
+ if entity_id not in [tags.get("thought_id"), tags.get("task_id")]:
1506
+ continue
1507
+
1508
+ # Convert TimeSeriesDataPoint to GraphNode for compatibility
1509
+ # TimeSeriesDataPoint doesn't directly map to audit entries, skip
1510
+ # This method seems to be looking for audit entries stored as timeseries
1511
+ # but TimeSeriesDataPoint is for metrics, not audit entries
1512
+ continue
1513
+
1514
+ return results
1515
+
1516
+ async def query_events(
1517
+ self,
1518
+ event_type: Optional[str] = None,
1519
+ start_time: Optional[datetime] = None,
1520
+ end_time: Optional[datetime] = None,
1521
+ limit: int = 100,
1522
+ ) -> List["AuditLogEntry"]:
1523
+ """Query audit events."""
1524
+ # Call query_audit_trail directly with parameters
1525
+ from ciris_engine.schemas.services.graph.audit import AuditQuery
1526
+
1527
+ query = AuditQuery(
1528
+ start_time=start_time, end_time=end_time, action_types=[event_type] if event_type else None, limit=limit
1529
+ )
1530
+ entries = await self.query_audit_trail(query)
1531
+
1532
+ # Convert to AuditLogEntry format
1533
+ from ciris_engine.schemas.audit.core import AuditLogEntry, EventPayload
1534
+
1535
+ result = []
1536
+ for entry in entries:
1537
+ # Create EventPayload from entry context
1538
+ event_payload = EventPayload(
1539
+ action=entry.action, user_id=entry.actor, service_name=getattr(entry, "resource", "audit_service")
1540
+ )
1541
+
1542
+ # Create AuditLogEntry
1543
+ entity_id = entry.context.correlation_id or ""
1544
+ log_entry = AuditLogEntry(
1545
+ event_id=entry.id,
1546
+ event_timestamp=entry.timestamp,
1547
+ event_type=entry.action,
1548
+ originator_id=entry.actor,
1549
+ target_id=entity_id,
1550
+ event_summary=f"{entry.action} by {entry.actor}",
1551
+ event_payload=event_payload,
1552
+ thought_id=entity_id if entity_id.startswith("thought") else None,
1553
+ entry_hash=entry.signature,
1554
+ )
1555
+ result.append(log_entry)
1556
+ return result
1557
+
1558
+ def _convert_entry_to_audit_log_dict(self, entry: AuditRequest) -> JSONDict:
1559
+ """Convert audit entry to audit log dictionary format."""
1560
+ return {
1561
+ "event_id": entry.entry_id,
1562
+ "event_type": entry.event_type,
1563
+ "timestamp": entry.timestamp.isoformat() if entry.timestamp else None,
1564
+ "user_id": entry.actor,
1565
+ "data": entry.details,
1566
+ "metadata": {"outcome": entry.outcome} if entry.outcome else {},
1567
+ }
1568
+
1569
+ async def _search_event_in_memory_bus(self, event_id: str) -> Optional[JSONDict]:
1570
+ """Search for event in memory bus."""
1571
+ if not self._memory_bus:
1572
+ return None
1573
+
1574
+ query = MemoryQuery(
1575
+ node_id=event_id, scope=GraphScope.LOCAL, type=NodeType.AUDIT_ENTRY, include_edges=False, depth=1
1576
+ )
1577
+
1578
+ nodes = await self._memory_bus.recall(query)
1579
+ if not nodes or len(nodes) == 0:
1580
+ return None
1581
+
1582
+ entry = self._tsdb_to_audit_entry(nodes[0])
1583
+ if not entry:
1584
+ return None
1585
+
1586
+ return self._convert_entry_to_audit_log_dict(entry)
1587
+
1588
+ def _search_event_in_recent_cache(self, event_id: str) -> Optional[JSONDict]:
1589
+ """Search for event in recent entries cache."""
1590
+ for entry in self._recent_entries:
1591
+ if entry.entry_id == event_id:
1592
+ return self._convert_entry_to_audit_log_dict(entry)
1593
+ return None
1594
+
1595
+ async def get_event_by_id(self, event_id: str) -> Optional["AuditLogEntry"]:
1596
+ """Get specific audit event by ID."""
1597
+ from ciris_engine.schemas.audit.core import AuditLogEntry, EventPayload
1598
+
1599
+ # Try memory bus first
1600
+ result_dict = await self._search_event_in_memory_bus(event_id)
1601
+ if not result_dict:
1602
+ # Fall back to recent cache
1603
+ result_dict = self._search_event_in_recent_cache(event_id)
1604
+
1605
+ if not result_dict:
1606
+ return None
1607
+
1608
+ # Convert dict to AuditLogEntry
1609
+ return AuditLogEntry(
1610
+ event_id=result_dict.get("event_id", event_id),
1611
+ event_timestamp=result_dict.get("timestamp"),
1612
+ event_type=result_dict.get("event_type", ""),
1613
+ originator_id=result_dict.get("user_id", ""),
1614
+ target_id=result_dict.get("user_id", ""),
1615
+ event_summary=f"{result_dict.get('event_type', '')} event",
1616
+ event_payload=EventPayload(
1617
+ action=result_dict.get("event_type", ""),
1618
+ service_name="audit_service",
1619
+ user_id=result_dict.get("user_id", ""),
1620
+ ),
1621
+ )
1622
+
1623
+ def _audit_request_to_entry(self, req: AuditRequest) -> AuditEntry:
1624
+ """Convert AuditRequest to AuditEntry."""
1625
+ return AuditEntryNode(
1626
+ id=f"audit_{req.entry_id}",
1627
+ action=req.event_type,
1628
+ actor=req.actor,
1629
+ timestamp=req.timestamp,
1630
+ context=AuditEntryContext(
1631
+ service_name=req.details.get("handler_name", ""),
1632
+ correlation_id=req.entity_id,
1633
+ additional_data={k: str(v) for k, v in req.details.items()},
1634
+ ),
1635
+ signature=None,
1636
+ hash_chain=None,
1637
+ scope=GraphScope.LOCAL,
1638
+ attributes={},
1639
+ )
1640
+
1641
+ # Required methods for BaseGraphService
1642
+
1643
+ def get_service_type(self) -> ServiceType:
1644
+ """Get the service type."""
1645
+ return ServiceType.AUDIT
1646
+
1647
+ def _get_actions(self) -> List[str]:
1648
+ """Get the list of actions this service supports."""
1649
+ return [
1650
+ "log_action",
1651
+ "log_event",
1652
+ "log_request",
1653
+ "get_audit_trail",
1654
+ "query_audit_trail",
1655
+ "query_by_actor",
1656
+ "query_by_time_range",
1657
+ "export_audit_log",
1658
+ "verify_integrity",
1659
+ "verify_signatures",
1660
+ "get_complete_verification_report",
1661
+ "query_events",
1662
+ "get_event_by_id",
1663
+ "verify_audit_integrity",
1664
+ ]
1665
+
1666
+ def _check_dependencies(self) -> bool:
1667
+ """Check if all dependencies are satisfied."""
1668
+ # Check parent dependencies (memory bus)
1669
+ if not super()._check_dependencies():
1670
+ return False
1671
+
1672
+ # No need to check hash_chain here - it's initialized during start()
1673
+ # The hash_chain is an internal component, not an external dependency
1674
+
1675
+ return True