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,1120 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import logging
5
+ from datetime import datetime, timedelta, timezone
6
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
7
+ from uuid import uuid4
8
+
9
+ from ciris_engine.constants import UTC_TIMEZONE_SUFFIX
10
+ from ciris_engine.logic.config import get_sqlite_db_full_path
11
+ from ciris_engine.logic.persistence import get_db_connection, initialize_database
12
+ from ciris_engine.logic.secrets.service import SecretsService
13
+ from ciris_engine.logic.services.base_graph_service import BaseGraphService, GraphNodeConvertible
14
+ from ciris_engine.logic.utils.jsondict_helpers import get_dict, get_list, get_str
15
+ from ciris_engine.protocols.services import GraphMemoryServiceProtocol, MemoryService
16
+ from ciris_engine.protocols.services.lifecycle.time import TimeServiceProtocol
17
+ from ciris_engine.schemas.runtime.enums import ServiceType
18
+ from ciris_engine.schemas.runtime.memory import TimeSeriesDataPoint
19
+ from ciris_engine.schemas.secrets.service import DecapsulationContext
20
+ from ciris_engine.schemas.services.graph.attributes import AnyNodeAttributes, LogNodeAttributes, TelemetryNodeAttributes
21
+ from ciris_engine.schemas.services.graph.memory import MemorySearchFilter
22
+ from ciris_engine.schemas.services.graph_core import GraphEdge, GraphNode, GraphNodeAttributes, GraphScope, NodeType
23
+ from ciris_engine.schemas.services.operations import MemoryOpResult, MemoryOpStatus, MemoryQuery
24
+ from ciris_engine.schemas.types import JSONDict, JSONList, JSONValue
25
+
26
+ # No longer using psutil - resource_monitor handles process metrics
27
+
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+
32
+ class DateTimeEncoder(json.JSONEncoder):
33
+ """Custom JSON encoder that handles datetime objects and Pydantic models."""
34
+
35
+ def default(self, obj: object) -> Union[str, JSONDict, JSONList, int, float, bool, None]:
36
+ if isinstance(obj, datetime):
37
+ return obj.isoformat()
38
+ # Handle Pydantic models
39
+ if hasattr(obj, "model_dump"):
40
+ return obj.model_dump() # type: ignore[no-any-return]
41
+ # Handle any object with to_dict method
42
+ if hasattr(obj, "to_dict"):
43
+ return obj.to_dict() # type: ignore[no-any-return]
44
+ return super().default(obj) # type: ignore[no-any-return]
45
+
46
+
47
+ class LocalGraphMemoryService(BaseGraphService, MemoryService, GraphMemoryServiceProtocol):
48
+ """Graph memory backed by the persistence database."""
49
+
50
+ def __init__(
51
+ self,
52
+ db_path: Optional[str] = None,
53
+ secrets_service: Optional[SecretsService] = None,
54
+ time_service: Optional[TimeServiceProtocol] = None,
55
+ ) -> None:
56
+ # Initialize BaseGraphService - LocalGraphMemoryService doesn't use memory_bus
57
+ super().__init__(memory_bus=None, time_service=time_service)
58
+
59
+ import logging
60
+
61
+ logger_temp = logging.getLogger(__name__)
62
+ logger_temp.debug(f"LocalGraphMemoryService.__init__ - received db_path: {db_path!r}")
63
+
64
+ self.db_path = db_path or get_sqlite_db_full_path()
65
+ logger_temp.debug(f"LocalGraphMemoryService.__init__ - self.db_path set to: {self.db_path!r}")
66
+
67
+ initialize_database(db_path=self.db_path)
68
+ self.secrets_service = secrets_service # Must be provided, not created here
69
+ self._start_time: Optional[datetime] = None
70
+
71
+ async def memorize(self, node: GraphNode) -> "MemoryOpResult[GraphNode]":
72
+ """Store a node with automatic secrets detection and processing."""
73
+ self._track_request()
74
+ try:
75
+ # Process secrets in node attributes before storing
76
+ processed_node = await self._process_secrets_for_memorize(node)
77
+
78
+ from ciris_engine.logic.persistence.models import graph as persistence
79
+
80
+ if self._time_service:
81
+ persistence.add_graph_node(processed_node, db_path=self.db_path, time_service=self._time_service)
82
+ else:
83
+ raise RuntimeError("TimeService is required for adding graph nodes")
84
+ return MemoryOpResult[GraphNode](status=MemoryOpStatus.OK, data=processed_node)
85
+ except Exception as e:
86
+ logger.exception("Error storing node %s: %s", node.id, e)
87
+ return MemoryOpResult[GraphNode](status=MemoryOpStatus.DENIED, error=str(e))
88
+
89
+ async def recall(self, recall_query: MemoryQuery) -> List[GraphNode]:
90
+ """Recall nodes from memory based on query."""
91
+ self._track_request()
92
+ try:
93
+ from ciris_engine.logic.persistence import get_all_graph_nodes
94
+ from ciris_engine.logic.persistence.models import graph as persistence
95
+
96
+ logger.debug(
97
+ f"Memory recall called with node_id='{recall_query.node_id}', scope={recall_query.scope}, type={recall_query.type}"
98
+ )
99
+
100
+ # Check if this is a wildcard query
101
+ if recall_query.node_id in ["*", "%", "all"]:
102
+ return await self._recall_wildcard(recall_query)
103
+ else:
104
+ return await self._recall_single_node(recall_query)
105
+
106
+ except Exception as e:
107
+ logger.exception("Error recalling nodes for query %s: %s", recall_query.node_id, e)
108
+ return []
109
+
110
+ async def _recall_wildcard(self, recall_query: MemoryQuery) -> List[GraphNode]:
111
+ """Handle wildcard recall queries."""
112
+ from ciris_engine.logic.persistence import get_all_graph_nodes
113
+
114
+ logger.debug(f"Memory recall: wildcard query with scope {recall_query.scope}, type {recall_query.type}")
115
+
116
+ # Use the new get_all_graph_nodes function
117
+ nodes = get_all_graph_nodes(
118
+ scope=recall_query.scope,
119
+ node_type=recall_query.type.value if recall_query.type else None,
120
+ limit=100, # Reasonable default limit for wildcard queries
121
+ db_path=self.db_path,
122
+ )
123
+ logger.debug(f"Wildcard query returned {len(nodes)} nodes")
124
+
125
+ # Process secrets and edges for all nodes
126
+ processed_nodes = []
127
+ for node in nodes:
128
+ processed_node = await self._process_node_for_recall(node, recall_query.include_edges)
129
+ processed_nodes.append(processed_node)
130
+
131
+ return processed_nodes
132
+
133
+ async def _recall_single_node(self, recall_query: MemoryQuery) -> List[GraphNode]:
134
+ """Handle single node recall queries."""
135
+ from ciris_engine.logic.persistence.models import graph as persistence
136
+
137
+ logger.debug(f"Memory recall: getting node {recall_query.node_id} scope {recall_query.scope}")
138
+ stored = persistence.get_graph_node(recall_query.node_id, recall_query.scope, db_path=self.db_path)
139
+ if not stored:
140
+ return []
141
+
142
+ # Process secrets in the node's attributes
143
+ if stored.attributes:
144
+ processed_attrs = await self._process_secrets_for_recall(stored.attributes, "recall")
145
+ stored = GraphNode(
146
+ id=stored.id,
147
+ type=stored.type,
148
+ scope=stored.scope,
149
+ attributes=processed_attrs,
150
+ version=stored.version,
151
+ updated_by=stored.updated_by,
152
+ updated_at=stored.updated_at,
153
+ )
154
+
155
+ # Handle edges if requested
156
+ if recall_query.include_edges and recall_query.depth > 0:
157
+ stored = await self._process_node_with_edges(stored, include_edges=True)
158
+
159
+ # If depth > 1, fetch connected nodes recursively
160
+ if recall_query.depth > 1:
161
+ return await self._fetch_connected_nodes(stored, recall_query.depth)
162
+
163
+ return [stored]
164
+
165
+ async def _process_node_for_recall(self, node: GraphNode, include_edges: bool) -> GraphNode:
166
+ """Process a single node for recall, handling secrets and edges."""
167
+ # Process attributes - always returns dict for compatibility
168
+ processed_attrs: JSONDict = {}
169
+ if node.attributes:
170
+ processed_attrs = await self._process_secrets_for_recall(node.attributes, "recall")
171
+
172
+ # Create node with processed attributes
173
+ processed_node = GraphNode(
174
+ id=node.id,
175
+ type=node.type,
176
+ scope=node.scope,
177
+ attributes=processed_attrs,
178
+ version=node.version,
179
+ updated_by=node.updated_by,
180
+ updated_at=node.updated_at,
181
+ )
182
+
183
+ # Include edges if requested
184
+ if include_edges:
185
+ processed_node = await self._process_node_with_edges(processed_node, include_edges=True)
186
+
187
+ return processed_node
188
+
189
+ async def forget(self, node: GraphNode) -> "MemoryOpResult[GraphNode]":
190
+ """Forget a node and clean up any associated secrets."""
191
+ self._track_request()
192
+ try:
193
+ # First retrieve the node to check for secrets
194
+ from ciris_engine.logic.persistence.models import graph as persistence
195
+
196
+ stored = persistence.get_graph_node(node.id, node.scope, db_path=self.db_path)
197
+ if stored:
198
+ self._process_secrets_for_forget(stored.attributes)
199
+
200
+ from ciris_engine.logic.persistence.models import graph as persistence
201
+
202
+ persistence.delete_graph_node(node.id, node.scope, db_path=self.db_path)
203
+ return MemoryOpResult[GraphNode](status=MemoryOpStatus.OK, data=node)
204
+ except Exception as e:
205
+ logger.exception("Error forgetting node %s: %s", node.id, e)
206
+ return MemoryOpResult[GraphNode](status=MemoryOpStatus.DENIED, error=str(e))
207
+
208
+ async def export_identity_context(self) -> str:
209
+ """
210
+ Export agent identity context as formatted text.
211
+
212
+ Uses format_agent_identity() to convert raw graph node data into
213
+ human-readable text with shutdown history.
214
+ """
215
+ import asyncio
216
+
217
+ from ciris_engine.logic.formatters.identity import format_agent_identity
218
+
219
+ def _query_identity() -> str:
220
+ with get_db_connection(db_path=self.db_path) as conn:
221
+ cursor = conn.cursor()
222
+ cursor.execute(
223
+ "SELECT node_id, attributes_json FROM graph_nodes WHERE scope = ?", (GraphScope.IDENTITY.value,)
224
+ )
225
+ rows = cursor.fetchall()
226
+
227
+ # If we have identity nodes, format the first one
228
+ # (typically there's only one identity node per agent)
229
+ if rows:
230
+ # Handle PostgreSQL JSONB vs SQLite TEXT
231
+ attrs_json = rows[0]["attributes_json"]
232
+ if attrs_json:
233
+ attrs = attrs_json if isinstance(attrs_json, dict) else json.loads(attrs_json)
234
+ else:
235
+ attrs = {}
236
+ return format_agent_identity(attrs)
237
+
238
+ return ""
239
+
240
+ loop = asyncio.get_event_loop()
241
+ return await loop.run_in_executor(None, _query_identity)
242
+
243
+ async def _process_secrets_for_memorize(self, node: GraphNode) -> GraphNode:
244
+ """Process secrets in node attributes during memorization."""
245
+ if not node.attributes:
246
+ return node
247
+
248
+ # Convert attributes to JSON string for processing
249
+ # Handle both dict and Pydantic model attributes
250
+ if hasattr(node.attributes, "model_dump"):
251
+ attributes_dict = node.attributes.model_dump()
252
+ else:
253
+ attributes_dict = node.attributes
254
+ attributes_str = json.dumps(attributes_dict, cls=DateTimeEncoder)
255
+
256
+ # Process for secrets detection and replacement
257
+ # SecretsService requires source_message_id
258
+ if not self.secrets_service:
259
+ logger.warning(
260
+ f"Secrets service unavailable for memorize operation on node {node.id}. "
261
+ f"Secrets will NOT be encrypted. This may expose sensitive data."
262
+ )
263
+ return node
264
+ processed_text, secret_refs = await self.secrets_service.process_incoming_text(
265
+ attributes_str, source_message_id=f"memorize_{node.id}"
266
+ )
267
+
268
+ # Create new node with processed attributes
269
+ processed_attributes = json.loads(processed_text) if processed_text != attributes_str else node.attributes
270
+
271
+ # Add secret references to node metadata if any were found
272
+ if secret_refs:
273
+ if isinstance(processed_attributes, dict):
274
+ refs_list = get_list(processed_attributes, "secret_refs", [])
275
+ refs_list.extend([ref.uuid for ref in secret_refs])
276
+ processed_attributes["secret_refs"] = refs_list
277
+ logger.info(f"Stored {len(secret_refs)} secret references in memory node {node.id}")
278
+
279
+ return GraphNode(
280
+ id=node.id,
281
+ type=node.type,
282
+ scope=node.scope,
283
+ attributes=processed_attributes,
284
+ version=node.version,
285
+ updated_by=node.updated_by,
286
+ updated_at=node.updated_at,
287
+ )
288
+
289
+ async def _process_secrets_for_recall(
290
+ self, attributes: AnyNodeAttributes | GraphNodeAttributes | JSONDict, action_type: str
291
+ ) -> JSONDict:
292
+ """Process secrets in recalled attributes for potential decryption."""
293
+ if not attributes:
294
+ return {}
295
+
296
+ # Convert GraphNodeAttributes to dict if needed
297
+ attributes_dict: JSONDict
298
+ if hasattr(attributes, "model_dump"):
299
+ attributes_dict = attributes.model_dump()
300
+ else: # isinstance(attributes, dict)
301
+ attributes_dict = attributes
302
+
303
+ secret_refs = attributes_dict.get("secret_refs", [])
304
+ if not secret_refs:
305
+ return attributes_dict
306
+
307
+ should_decrypt = False
308
+ if self.secrets_service and hasattr(self.secrets_service, "filter"):
309
+ should_decrypt = action_type in getattr(
310
+ self.secrets_service.filter.detection_config, "auto_decrypt_for_actions", ["speak", "tool"]
311
+ )
312
+
313
+ if should_decrypt:
314
+ _attributes_str = json.dumps(attributes_dict, cls=DateTimeEncoder)
315
+
316
+ if not self.secrets_service:
317
+ logger.warning(
318
+ f"Secrets service unavailable for recall operation. "
319
+ f"Secrets will NOT be decrypted for action_type={action_type}. "
320
+ f"This may prevent proper secret handling."
321
+ )
322
+ return attributes_dict
323
+ decapsulated_attributes = await self.secrets_service.decapsulate_secrets_in_parameters(
324
+ action_type=action_type,
325
+ action_params=attributes_dict,
326
+ context=DecapsulationContext(action_type=action_type, thought_id="memory_recall", user_id="system"),
327
+ )
328
+
329
+ if decapsulated_attributes != attributes_dict:
330
+ logger.info(f"Auto-decrypted secrets in recalled data for {action_type}")
331
+ # Type assertion: decapsulate_secrets_in_parameters should return dict
332
+ assert isinstance(decapsulated_attributes, dict)
333
+ return decapsulated_attributes
334
+
335
+ return attributes_dict
336
+
337
+ def _process_secrets_for_forget(self, attributes: AnyNodeAttributes | GraphNodeAttributes | JSONDict) -> None:
338
+ """Clean up secrets when forgetting a node."""
339
+ if not attributes:
340
+ return
341
+
342
+ # Convert GraphNodeAttributes to dict if needed
343
+ attributes_dict: JSONDict
344
+ if hasattr(attributes, "model_dump"):
345
+ attributes_dict = attributes.model_dump()
346
+ else: # isinstance(attributes, dict)
347
+ attributes_dict = attributes
348
+
349
+ # Check for secret references
350
+ secret_refs = attributes_dict.get("secret_refs", [])
351
+ if secret_refs:
352
+ # Note: We don't automatically delete secrets on FORGET since they might be
353
+ # referenced elsewhere. This would need to be a conscious decision by the agent.
354
+ if isinstance(secret_refs, list):
355
+ logger.info(f"Node being forgotten contained {len(secret_refs)} secret references")
356
+ else:
357
+ logger.info("Node being forgotten contained secret references")
358
+
359
+ # Could implement reference counting here in the future if needed
360
+
361
+ async def recall_timeseries(
362
+ self,
363
+ scope: str = "default",
364
+ hours: int = 24,
365
+ correlation_types: Optional[List[str]] = None,
366
+ start_time: Optional[datetime] = None,
367
+ end_time: Optional[datetime] = None,
368
+ ) -> List[TimeSeriesDataPoint]:
369
+ """
370
+ Recall time-series data from TSDB graph nodes.
371
+
372
+ Args:
373
+ scope: The memory scope to search (mapped to TSDB tags)
374
+ hours: Number of hours to look back (ignored if start_time/end_time provided)
375
+ correlation_types: Optional filter by correlation types (for compatibility)
376
+ start_time: Specific start time for the query (overrides hours)
377
+ end_time: Specific end time for the query (defaults to now if not provided)
378
+
379
+ Returns:
380
+ List of time-series data points from graph nodes
381
+ """
382
+ self._track_request()
383
+ try:
384
+ # Calculate time window
385
+ if not self._time_service:
386
+ raise RuntimeError("TimeService is required for recall_timeseries")
387
+
388
+ # Handle time range parameters
389
+ if start_time and end_time:
390
+ # Use explicit time range
391
+ pass
392
+ elif start_time and not end_time:
393
+ # Start time provided, use now as end
394
+ end_time = self._time_service.now()
395
+ else:
396
+ # Fall back to hours-based calculation (backward compatible)
397
+ end_time = end_time or self._time_service.now()
398
+ start_time = end_time - timedelta(hours=hours)
399
+
400
+ # Query TSDB_DATA nodes directly from graph_nodes table
401
+ data_points: List[TimeSeriesDataPoint] = []
402
+
403
+ # Run database query in thread pool to avoid blocking event loop
404
+ import asyncio
405
+
406
+ loop = asyncio.get_event_loop()
407
+
408
+ def _query_tsdb_nodes() -> List[Any]:
409
+ from ciris_engine.logic.persistence.db.dialect import get_adapter
410
+
411
+ adapter = get_adapter()
412
+ with get_db_connection(db_path=self.db_path) as conn:
413
+ cursor = conn.cursor()
414
+
415
+ # Query for TSDB_DATA nodes in the time range
416
+ # ORDER BY DESC to get most recent metrics first
417
+ # PostgreSQL: created_at is already TIMESTAMP, no conversion needed
418
+ # SQLite: created_at is TEXT, use datetime() for comparison
419
+ if adapter.is_postgresql():
420
+ sql = """
421
+ SELECT node_id, attributes_json, created_at
422
+ FROM graph_nodes
423
+ WHERE node_type = 'tsdb_data'
424
+ AND scope = ?
425
+ AND created_at >= ?
426
+ AND created_at <= ?
427
+ ORDER BY created_at DESC
428
+ LIMIT 1000
429
+ """
430
+ else:
431
+ sql = """
432
+ SELECT node_id, attributes_json, created_at
433
+ FROM graph_nodes
434
+ WHERE node_type = 'tsdb_data'
435
+ AND scope = ?
436
+ AND datetime(created_at) >= datetime(?)
437
+ AND datetime(created_at) <= datetime(?)
438
+ ORDER BY created_at DESC
439
+ LIMIT 1000
440
+ """
441
+
442
+ cursor.execute(sql, (scope, start_time.isoformat(), end_time.isoformat()))
443
+ return cursor.fetchall()
444
+
445
+ rows = await loop.run_in_executor(None, _query_tsdb_nodes)
446
+
447
+ for row in rows:
448
+ try:
449
+ # Parse attributes - handle PostgreSQL JSONB vs SQLite TEXT
450
+ attrs_json = row["attributes_json"]
451
+ if attrs_json:
452
+ attrs = attrs_json if isinstance(attrs_json, dict) else json.loads(attrs_json)
453
+ else:
454
+ attrs = {}
455
+
456
+ # Extract metric data
457
+ metric_name = attrs.get("metric_name")
458
+ metric_value = attrs.get("value")
459
+
460
+ if not metric_name or metric_value is None:
461
+ continue
462
+
463
+ # Get timestamp from created_at or attributes
464
+ timestamp_str = attrs.get("created_at", row["created_at"])
465
+ timestamp: datetime
466
+ if isinstance(timestamp_str, str):
467
+ # Handle both timezone-aware and naive timestamps
468
+ if "Z" in timestamp_str:
469
+ timestamp = datetime.fromisoformat(timestamp_str.replace("Z", UTC_TIMEZONE_SUFFIX))
470
+ elif "+" in timestamp_str or "-" in timestamp_str[-6:]:
471
+ timestamp = datetime.fromisoformat(timestamp_str)
472
+ else:
473
+ # Naive timestamp - assume UTC
474
+ timestamp = datetime.fromisoformat(timestamp_str)
475
+ if timestamp.tzinfo is None:
476
+ timestamp = timestamp.replace(tzinfo=timezone.utc)
477
+ else:
478
+ timestamp = timestamp_str if isinstance(timestamp_str, datetime) else datetime.now(timezone.utc)
479
+ # Ensure timezone awareness
480
+ if timestamp.tzinfo is None:
481
+ timestamp = timestamp.replace(tzinfo=timezone.utc)
482
+
483
+ # Get tags - check both 'labels' and 'metric_tags' for backward compatibility
484
+ # Database stores in 'labels', but some older code may use 'metric_tags'
485
+ metric_tags = attrs.get("labels", attrs.get("metric_tags", {}))
486
+ if not isinstance(metric_tags, dict):
487
+ metric_tags = {}
488
+
489
+ # Create data point
490
+ data_point = TimeSeriesDataPoint(
491
+ timestamp=timestamp,
492
+ metric_name=metric_name,
493
+ value=float(metric_value),
494
+ correlation_type="METRIC_DATAPOINT", # Default for metrics
495
+ tags=metric_tags,
496
+ source=attrs.get("created_by", "memory_service"),
497
+ )
498
+
499
+ data_points.append(data_point)
500
+
501
+ except Exception as e:
502
+ logger.warning(f"Error parsing TSDB node {row['node_id']}: {e}")
503
+ continue
504
+
505
+ # Sort by timestamp
506
+ data_points.sort(key=lambda x: x.timestamp)
507
+
508
+ logger.debug(f"Recalled {len(data_points)} time series data points from graph nodes")
509
+ return data_points
510
+
511
+ except Exception as e:
512
+ logger.exception(f"Error recalling timeseries data: {e}")
513
+ return []
514
+
515
+ async def memorize_metric(
516
+ self, metric_name: str, value: float, tags: Optional[Dict[str, str]] = None, scope: str = "local"
517
+ ) -> "MemoryOpResult[GraphNode]":
518
+ """
519
+ Convenience method to memorize a metric as a graph node.
520
+
521
+ Metrics are stored only as TSDB_DATA nodes in the graph, not as correlations,
522
+ to prevent double storage and aggregation issues.
523
+ """
524
+ self._track_request()
525
+ try:
526
+ # Create a graph node for the metric
527
+ if not self._time_service:
528
+ raise RuntimeError("TimeService is required for memorize_metric")
529
+ now = self._time_service.now()
530
+ # Use microsecond precision to ensure unique IDs
531
+ node_id = f"metric_{metric_name}_{int(now.timestamp() * 1000000)}"
532
+
533
+ # Create typed attributes with metric-specific data
534
+ telemetry_attrs = TelemetryNodeAttributes(
535
+ created_at=now,
536
+ updated_at=now,
537
+ created_by="memory_service",
538
+ tags=["metric", metric_name],
539
+ metric_name=metric_name,
540
+ metric_type="gauge", # Default metric type
541
+ value=value,
542
+ start_time=now,
543
+ end_time=now,
544
+ duration_seconds=0.0,
545
+ sample_count=1,
546
+ labels=tags or {},
547
+ service_name="memory_service",
548
+ )
549
+
550
+ node = GraphNode(
551
+ id=node_id,
552
+ type=NodeType.TSDB_DATA,
553
+ scope=GraphScope(scope),
554
+ attributes=telemetry_attrs, # Pass typed Pydantic model directly
555
+ updated_by="memory_service",
556
+ updated_at=now,
557
+ )
558
+
559
+ # Store in graph memory
560
+ memory_result = await self.memorize(node)
561
+
562
+ # No longer storing metrics as correlations - only as graph nodes
563
+ # This prevents double storage and inflated aggregation issues
564
+
565
+ return memory_result
566
+
567
+ except Exception as e:
568
+ logger.exception(f"Error memorizing metric {metric_name}: {e}")
569
+ return MemoryOpResult[GraphNode](status=MemoryOpStatus.DENIED, error=str(e))
570
+
571
+ async def create_edge(self, edge: GraphEdge) -> "MemoryOpResult[GraphEdge]":
572
+ """Create an edge between two nodes in the memory graph."""
573
+ self._track_request()
574
+ try:
575
+ from ciris_engine.logic.persistence.models.graph import add_graph_edge
576
+
577
+ edge_id = add_graph_edge(edge, db_path=self.db_path)
578
+ logger.info(f"Created edge {edge_id}: {edge.source} -{edge.relationship}-> {edge.target}")
579
+
580
+ return MemoryOpResult[GraphEdge](status=MemoryOpStatus.OK, data=edge)
581
+ except Exception as e:
582
+ logger.exception(f"Error creating edge: {e}")
583
+ return MemoryOpResult[GraphEdge](status=MemoryOpStatus.DENIED, error=str(e))
584
+
585
+ async def get_node_edges(self, node_id: str, scope: GraphScope) -> List[GraphEdge]:
586
+ """Get all edges connected to a node."""
587
+ try:
588
+ from ciris_engine.logic.persistence.models.graph import get_edges_for_node
589
+
590
+ edges = get_edges_for_node(node_id, scope, db_path=self.db_path)
591
+ return edges
592
+ except Exception as e:
593
+ logger.exception(f"Error getting edges for node {node_id}: {e}")
594
+ return []
595
+
596
+ async def memorize_log(
597
+ self, log_message: str, log_level: str = "INFO", tags: Optional[Dict[str, str]] = None, scope: str = "local"
598
+ ) -> "MemoryOpResult[GraphNode]":
599
+ """
600
+ Convenience method to memorize a log entry as both a graph node and TSDB correlation.
601
+ """
602
+ self._track_request()
603
+ try:
604
+ # Import correlation models here to avoid circular imports
605
+ from ciris_engine.logic.persistence.models.correlations import add_correlation
606
+ from ciris_engine.schemas.telemetry.core import (
607
+ CorrelationType,
608
+ ServiceCorrelation,
609
+ ServiceCorrelationStatus,
610
+ )
611
+
612
+ # Create a graph node for the log entry
613
+ if not self._time_service:
614
+ raise RuntimeError("TimeService is required for memorize_log")
615
+ now = self._time_service.now()
616
+ node_id = f"log_{log_level}_{int(now.timestamp())}"
617
+
618
+ # Create typed attributes with log-specific data
619
+ log_attrs = LogNodeAttributes(
620
+ created_at=now,
621
+ updated_at=now,
622
+ created_by="memory_service",
623
+ tags=["log", log_level.lower()],
624
+ log_message=log_message,
625
+ log_level=log_level,
626
+ log_tags=tags or {},
627
+ retention_policy="raw",
628
+ )
629
+
630
+ node = GraphNode(
631
+ id=node_id,
632
+ type=NodeType.TSDB_DATA,
633
+ scope=GraphScope(scope),
634
+ attributes=log_attrs, # Pass typed Pydantic model directly
635
+ updated_by="memory_service",
636
+ updated_at=now,
637
+ )
638
+
639
+ # Store in graph memory
640
+ memory_result = await self.memorize(node)
641
+
642
+ # Also store as TSDB correlation
643
+ correlation = ServiceCorrelation(
644
+ correlation_id=str(uuid4()),
645
+ service_type="memory",
646
+ handler_name="memory_service",
647
+ action_type="memorize_log",
648
+ correlation_type=CorrelationType.LOG_ENTRY,
649
+ timestamp=now,
650
+ created_at=now,
651
+ updated_at=now,
652
+ tags=(
653
+ {**tags, "scope": scope, "message": log_message}
654
+ if tags
655
+ else {"scope": scope, "message": log_message}
656
+ ),
657
+ status=ServiceCorrelationStatus.COMPLETED,
658
+ retention_policy="raw",
659
+ request_data=None,
660
+ response_data=None,
661
+ metric_data=None,
662
+ log_data=None,
663
+ trace_context=None,
664
+ ttl_seconds=None,
665
+ parent_correlation_id=None,
666
+ )
667
+
668
+ if self._time_service:
669
+ add_correlation(correlation, db_path=self.db_path, time_service=self._time_service)
670
+ else:
671
+ raise RuntimeError("TimeService is required for add_correlation")
672
+
673
+ return memory_result
674
+
675
+ except Exception as e:
676
+ logger.exception(f"Error memorizing log entry: {e}")
677
+ return MemoryOpResult[GraphNode](status=MemoryOpStatus.DENIED, error=str(e))
678
+
679
+ # ============================================================================
680
+ # GRAPH PROTOCOL METHODS
681
+ # ============================================================================
682
+
683
+ async def search(self, query: str, filters: Optional[MemorySearchFilter] = None) -> List[GraphNode]:
684
+ """Search memories in the graph."""
685
+ self._track_request()
686
+ logger.debug(f"Memory search START: query='{query}', filters={filters}")
687
+ try:
688
+ # Parse query for search terms and filters
689
+ search_terms, query_node_type, query_scope = self._parse_search_query(query)
690
+
691
+ # Extract filters, preferring query string values
692
+ # Convert filter scope string to GraphScope enum
693
+ filter_scope: Optional[GraphScope] = None
694
+ if filters and hasattr(filters, "scope") and filters.scope:
695
+ try:
696
+ filter_scope = GraphScope(filters.scope)
697
+ except ValueError:
698
+ filter_scope = None
699
+ scope = query_scope or filter_scope or GraphScope.LOCAL
700
+ node_type = query_node_type or (filters.node_type if filters and hasattr(filters, "node_type") else None)
701
+ limit = filters.limit if filters and hasattr(filters, "limit") and filters.limit else 100
702
+
703
+ # Fetch nodes based on type
704
+ nodes = await self._fetch_nodes_for_search(scope, node_type, limit)
705
+
706
+ # Filter by content if search terms exist
707
+ if search_terms:
708
+ nodes = self._filter_nodes_by_content(nodes, search_terms)
709
+
710
+ # Process secrets for all nodes
711
+ return await self._process_nodes_for_search(nodes)
712
+
713
+ except Exception as e:
714
+ logger.exception(f"Error searching graph: {e}")
715
+ return []
716
+
717
+ async def _fetch_nodes_for_search(self, scope: GraphScope, node_type: Optional[str], limit: int) -> List[GraphNode]:
718
+ """Fetch nodes for search based on scope and type."""
719
+ from ciris_engine.logic.persistence import get_all_graph_nodes, get_nodes_by_type
720
+
721
+ if node_type:
722
+ return get_nodes_by_type(
723
+ node_type=node_type,
724
+ scope=scope if isinstance(scope, GraphScope) else GraphScope.LOCAL,
725
+ limit=limit,
726
+ db_path=self.db_path,
727
+ )
728
+ else:
729
+ return get_all_graph_nodes(
730
+ scope=scope if isinstance(scope, GraphScope) else GraphScope.LOCAL,
731
+ limit=limit,
732
+ db_path=self.db_path,
733
+ )
734
+
735
+ async def _process_nodes_for_search(self, nodes: List[GraphNode]) -> List[GraphNode]:
736
+ """Process nodes for search, handling secrets."""
737
+ processed_nodes = []
738
+ for node in nodes:
739
+ if node.attributes:
740
+ processed_attrs = await self._process_secrets_for_recall(node.attributes, "search")
741
+ processed_node = GraphNode(
742
+ id=node.id,
743
+ type=node.type,
744
+ scope=node.scope,
745
+ attributes=processed_attrs,
746
+ version=node.version,
747
+ updated_by=node.updated_by,
748
+ updated_at=node.updated_at,
749
+ )
750
+ processed_nodes.append(processed_node)
751
+ else:
752
+ processed_nodes.append(node)
753
+
754
+ return processed_nodes
755
+
756
+ # ============================================================================
757
+ # SERVICE PROTOCOL METHODS
758
+ # ============================================================================
759
+
760
+ async def start(self) -> None:
761
+ """Start the memory service."""
762
+ await super().start()
763
+ self._initialized = True
764
+ if self._time_service:
765
+ self._start_time = self._time_service.now()
766
+ logger.info("LocalGraphMemoryService started")
767
+
768
+ async def stop(self) -> None:
769
+ """Stop the memory service."""
770
+ logger.info("LocalGraphMemoryService stopped")
771
+ await super().stop()
772
+
773
+ def _collect_custom_metrics(self) -> Dict[str, float]:
774
+ """Collect memory-specific metrics from v1.4.3 set."""
775
+ metrics = super()._collect_custom_metrics()
776
+
777
+ # Count graph nodes and edges
778
+ node_count = 0
779
+ edge_count = 0
780
+ storage_size_mb = 0.0
781
+
782
+ try:
783
+ with get_db_connection(db_path=self.db_path) as conn:
784
+ cursor = conn.cursor()
785
+
786
+ # Get node count
787
+ cursor.execute("SELECT COUNT(*) FROM graph_nodes")
788
+ result = cursor.fetchone()
789
+ node_count = result[0] if result else 0
790
+
791
+ # Get edge count
792
+ cursor.execute("SELECT COUNT(*) FROM graph_edges")
793
+ result = cursor.fetchone()
794
+ edge_count = result[0] if result else 0
795
+
796
+ except Exception:
797
+ pass
798
+
799
+ # Get database file size
800
+ try:
801
+ import os
802
+
803
+ if os.path.exists(self.db_path):
804
+ storage_size_mb = os.path.getsize(self.db_path) / (1024 * 1024)
805
+ except (OSError, IOError, ImportError):
806
+ # Ignore file system and import errors when checking storage size
807
+ pass
808
+
809
+ # Calculate uptime in seconds
810
+ uptime_seconds = 0.0
811
+ if self._start_time and self._time_service:
812
+ uptime_delta = self._time_service.now() - self._start_time
813
+ uptime_seconds = uptime_delta.total_seconds()
814
+
815
+ # Return EXACTLY the 5 metrics from v1.4.3 set - no other metrics
816
+ memory_metrics = {
817
+ "memory_nodes_total": float(node_count),
818
+ "memory_edges_total": float(edge_count),
819
+ "memory_operations_total": float(self._request_count),
820
+ "memory_db_size_mb": storage_size_mb,
821
+ "memory_uptime_seconds": uptime_seconds,
822
+ # Add secrets_enabled metric for test compatibility
823
+ "secrets_enabled": 1.0 if self.secrets_service else 0.0,
824
+ }
825
+
826
+ # Update with the exact v1.4.3 memory metrics
827
+ metrics.update(memory_metrics)
828
+
829
+ return metrics
830
+
831
+ async def is_healthy(self) -> bool:
832
+ """Check if service is healthy."""
833
+ import asyncio
834
+
835
+ # Check if service is started
836
+ if not hasattr(self, "_started") or not self._started:
837
+ return False
838
+
839
+ def _check_database() -> bool:
840
+ try:
841
+ # Try a simple database operation
842
+ with get_db_connection(db_path=self.db_path) as conn:
843
+ cursor = conn.cursor()
844
+ cursor.execute("SELECT COUNT(*) FROM graph_nodes")
845
+ cursor.fetchone()
846
+ return True
847
+ except Exception:
848
+ return False
849
+
850
+ loop = asyncio.get_event_loop()
851
+ return await loop.run_in_executor(None, _check_database)
852
+
853
+ async def store_in_graph(self, node: Union[GraphNode, GraphNodeConvertible]) -> str:
854
+ """Store a node in the graph."""
855
+ # Convert to GraphNode if needed
856
+ if hasattr(node, "to_graph_node"):
857
+ graph_node = node.to_graph_node()
858
+ else:
859
+ graph_node = node
860
+
861
+ result = await self.memorize(graph_node)
862
+ return graph_node.id if result.status == MemoryOpStatus.OK else ""
863
+
864
+ async def query_graph(self, query: MemoryQuery) -> List[GraphNode]:
865
+ """Query the graph."""
866
+ return await self.recall(query)
867
+
868
+ def get_node_type(self) -> str:
869
+ """Get the type of nodes this service manages."""
870
+ return "ALL" # Memory service manages all node types
871
+
872
+ # Required methods for BaseGraphService
873
+
874
+ def get_service_type(self) -> ServiceType:
875
+ """Get the service type."""
876
+ return ServiceType.MEMORY
877
+
878
+ def _get_actions(self) -> List[str]:
879
+ """Get the list of actions this service supports."""
880
+ return [
881
+ "memorize",
882
+ "recall",
883
+ "forget",
884
+ "memorize_metric",
885
+ "memorize_log",
886
+ "recall_timeseries",
887
+ "export_identity_context",
888
+ "search",
889
+ "create_edge",
890
+ "get_node_edges",
891
+ ]
892
+
893
+ def _check_dependencies(self) -> bool:
894
+ """Check if all dependencies are satisfied."""
895
+ # Memory service doesn't use memory bus (it IS what memory bus uses)
896
+ # Check for optional dependencies
897
+ return True # Base memory service has no hard dependencies
898
+
899
+ # ============================================================================
900
+ # REFACTORED HELPER METHODS TO REDUCE COMPLEXITY
901
+ # ============================================================================
902
+
903
+ async def _process_node_with_edges(self, node: GraphNode, include_edges: bool = False) -> GraphNode:
904
+ """Process a node and optionally attach its edges."""
905
+ if not include_edges:
906
+ return node
907
+
908
+ from ciris_engine.logic.persistence.models.graph import get_edges_for_node
909
+
910
+ edges = get_edges_for_node(node.id, node.scope, db_path=self.db_path)
911
+ if not edges:
912
+ return node
913
+
914
+ # Convert edges to dict format
915
+ edges_data = [
916
+ {
917
+ "source": edge.source,
918
+ "target": edge.target,
919
+ "relationship": edge.relationship,
920
+ "weight": edge.weight,
921
+ "attributes": (
922
+ edge.attributes.model_dump() if hasattr(edge.attributes, "model_dump") else edge.attributes
923
+ ),
924
+ }
925
+ for edge in edges
926
+ ]
927
+
928
+ # Add edges to node attributes
929
+ if isinstance(node.attributes, dict):
930
+ node.attributes["_edges"] = edges_data
931
+ else:
932
+ attrs_dict = self._get_attributes_dict(node.attributes)
933
+ attrs_dict["_edges"] = edges_data
934
+ node = GraphNode(
935
+ id=node.id,
936
+ type=node.type,
937
+ scope=node.scope,
938
+ attributes=attrs_dict,
939
+ version=node.version,
940
+ updated_by=node.updated_by,
941
+ updated_at=node.updated_at,
942
+ )
943
+
944
+ return node
945
+
946
+ async def _fetch_connected_nodes(self, start_node: GraphNode, depth: int) -> List[GraphNode]:
947
+ """Fetch nodes connected to start_node up to specified depth."""
948
+ if depth <= 0:
949
+ return [start_node]
950
+
951
+ from ciris_engine.logic.persistence.models.graph import get_edges_for_node
952
+
953
+ visited_nodes = {start_node.id}
954
+ nodes_to_process = [(start_node, 0)]
955
+ all_nodes = [start_node]
956
+
957
+ while nodes_to_process:
958
+ current_node, current_depth = nodes_to_process.pop(0)
959
+
960
+ if current_depth >= depth - 1:
961
+ continue
962
+
963
+ # Get edges for current node
964
+ current_edges = get_edges_for_node(current_node.id, current_node.scope, db_path=self.db_path)
965
+
966
+ for edge in current_edges:
967
+ # Process this edge's connected node
968
+ result = await self._process_edge_connection(edge, current_node, visited_nodes, current_depth)
969
+ if result:
970
+ connected_node, should_continue = result
971
+ all_nodes.append(connected_node)
972
+ nodes_to_process.append((connected_node, current_depth + 1))
973
+
974
+ return all_nodes
975
+
976
+ async def _process_edge_connection(
977
+ self, edge: Any, current_node: GraphNode, visited_nodes: set[str], current_depth: int
978
+ ) -> Optional[Tuple[GraphNode, bool]]:
979
+ """Process a single edge connection and return the connected node if valid."""
980
+ from ciris_engine.logic.persistence.models import graph as persistence
981
+
982
+ # Determine the connected node ID
983
+ connected_id = edge.target if edge.source == current_node.id else edge.source
984
+
985
+ if connected_id in visited_nodes:
986
+ return None
987
+
988
+ # Fetch the connected node
989
+ connected_node = persistence.get_graph_node(connected_id, edge.scope, db_path=self.db_path)
990
+
991
+ if not connected_node:
992
+ return None
993
+
994
+ visited_nodes.add(connected_id)
995
+
996
+ # Process secrets if needed
997
+ if connected_node.attributes:
998
+ processed_attrs = await self._process_secrets_for_recall(connected_node.attributes, "recall")
999
+ connected_node = GraphNode(
1000
+ id=connected_node.id,
1001
+ type=connected_node.type,
1002
+ scope=connected_node.scope,
1003
+ attributes=processed_attrs,
1004
+ version=connected_node.version,
1005
+ updated_by=connected_node.updated_by,
1006
+ updated_at=connected_node.updated_at,
1007
+ )
1008
+
1009
+ # Process edges for the connected node
1010
+ connected_node = await self._process_node_with_edges(connected_node, include_edges=True)
1011
+
1012
+ return connected_node, True
1013
+
1014
+ def _apply_time_filters(self, nodes: List[GraphNode], filters: Optional[JSONDict]) -> List[GraphNode]:
1015
+ """Apply time-based filters to a list of nodes."""
1016
+ if not filters:
1017
+ return nodes
1018
+
1019
+ filtered = nodes
1020
+
1021
+ since_val = filters.get("since")
1022
+ if since_val:
1023
+ since_dt: datetime
1024
+ if isinstance(since_val, str):
1025
+ since_dt = datetime.fromisoformat(since_val)
1026
+ elif isinstance(since_val, datetime):
1027
+ since_dt = since_val
1028
+ else:
1029
+ # Skip invalid type
1030
+ return filtered
1031
+ filtered = [n for n in filtered if n.updated_at and n.updated_at >= since_dt]
1032
+
1033
+ until_val = filters.get("until")
1034
+ if until_val:
1035
+ until_dt: datetime
1036
+ if isinstance(until_val, str):
1037
+ until_dt = datetime.fromisoformat(until_val)
1038
+ elif isinstance(until_val, datetime):
1039
+ until_dt = until_val
1040
+ else:
1041
+ # Skip invalid type
1042
+ return filtered
1043
+ filtered = [n for n in filtered if n.updated_at and n.updated_at <= until_dt]
1044
+
1045
+ return filtered
1046
+
1047
+ def _apply_tag_filters(self, nodes: List[GraphNode], filters: Optional[JSONDict]) -> List[GraphNode]:
1048
+ """Apply tag-based filters to a list of nodes."""
1049
+ if not filters or "tags" not in filters:
1050
+ return nodes
1051
+
1052
+ tags_val = filters.get("tags", [])
1053
+ if not isinstance(tags_val, list):
1054
+ return nodes
1055
+
1056
+ filtered = []
1057
+ for n in nodes:
1058
+ if not n.attributes:
1059
+ continue
1060
+
1061
+ # Handle both dict and object attributes
1062
+ node_tags = None
1063
+ if isinstance(n.attributes, dict):
1064
+ node_tags = get_list(n.attributes, "tags", [])
1065
+ elif hasattr(n.attributes, "tags"):
1066
+ node_tags = n.attributes.tags
1067
+
1068
+ if node_tags and any(tag in node_tags for tag in tags_val):
1069
+ filtered.append(n)
1070
+
1071
+ return filtered
1072
+
1073
+ def _parse_search_query(self, query: str) -> Tuple[List[str], Optional[str], Optional[GraphScope]]:
1074
+ """Parse search query string for terms and filters."""
1075
+ if not query:
1076
+ return [], None, None
1077
+
1078
+ query_parts = query.split()
1079
+ search_terms = []
1080
+ node_type = None
1081
+ scope = None
1082
+
1083
+ for part in query_parts:
1084
+ if part.startswith("type:"):
1085
+ node_type = part.split(":")[1]
1086
+ elif part.startswith("scope:"):
1087
+ scope = GraphScope(part.split(":")[1].lower())
1088
+ else:
1089
+ search_terms.append(part.lower())
1090
+
1091
+ return search_terms, node_type, scope
1092
+
1093
+ def _filter_nodes_by_content(self, nodes: List[GraphNode], search_terms: List[str]) -> List[GraphNode]:
1094
+ """Filter nodes by search terms in content."""
1095
+ if not search_terms:
1096
+ return nodes
1097
+
1098
+ filtered = []
1099
+ for node in nodes:
1100
+ # Search in node ID
1101
+ if any(term in node.id.lower() for term in search_terms):
1102
+ filtered.append(node)
1103
+ continue
1104
+
1105
+ # Search in attributes
1106
+ if node.attributes:
1107
+ attrs_str = json.dumps(node.attributes, cls=DateTimeEncoder).lower()
1108
+ if any(term in attrs_str for term in search_terms):
1109
+ filtered.append(node)
1110
+
1111
+ return filtered
1112
+
1113
+ def _get_attributes_dict(self, attributes: Any) -> JSONDict:
1114
+ """Extract attributes as dictionary from various formats."""
1115
+ if hasattr(attributes, "model_dump"):
1116
+ return attributes.model_dump() # type: ignore[no-any-return]
1117
+ elif attributes:
1118
+ return dict(attributes)
1119
+ else:
1120
+ return {}