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,981 @@
1
+ """User management API routes."""
2
+
3
+ import logging
4
+ from datetime import datetime
5
+ from typing import Any, Dict, Generic, List, Optional, TypeVar
6
+
7
+ import aiofiles
8
+ from fastapi import APIRouter, Depends, HTTPException, Query, Request
9
+ from pydantic import BaseModel, ConfigDict, Field
10
+
11
+ from ciris_engine.schemas.api.auth import AuthContext, PermissionRequestResponse, PermissionRequestUser, UserRole
12
+ from ciris_engine.schemas.runtime.api import APIRole
13
+ from ciris_engine.schemas.services.authority_core import OAuthIdentityLink, WARole
14
+ from ciris_engine.schemas.types import JSONDict
15
+
16
+ from ..dependencies.auth import check_permissions, get_auth_context, get_auth_service
17
+ from ..services.auth_service import (
18
+ PERMISSION_MANAGE_USER_PERMISSIONS,
19
+ PERMISSION_USERS_DELETE,
20
+ PERMISSION_USERS_READ,
21
+ PERMISSION_USERS_WRITE,
22
+ PERMISSION_WA_MINT,
23
+ APIAuthService,
24
+ )
25
+
26
+ # Error message constants
27
+ ERROR_USER_NOT_FOUND = "User not found"
28
+ ERROR_USERNAME_EXISTS = "Username already exists"
29
+ ERROR_CREATE_USER_FAILED = "Failed to create user"
30
+ ERROR_CHANGE_PASSWORD_FAILED = "Failed to change password. Check current password."
31
+ ERROR_CANNOT_DEMOTE_SELF = "Cannot demote your own role"
32
+ ERROR_CANNOT_DEACTIVATE_SELF = "Cannot deactivate your own account"
33
+ ERROR_ONLY_ADMIN_MINT_WA = "Only ADMIN or higher can mint Wise Authorities"
34
+ ERROR_CANNOT_MINT_ROOT = "Cannot mint new ROOT authorities. ROOT is singular."
35
+ ERROR_INVALID_SIGNATURE = "Invalid ROOT signature"
36
+ ERROR_SIGNATURE_OR_KEY_REQUIRED = "Either signature or private_key_path must be provided"
37
+
38
+ router = APIRouter(prefix="/users", tags=["users"])
39
+
40
+ logger = logging.getLogger(__name__)
41
+
42
+
43
+ # Generic models
44
+ T = TypeVar("T")
45
+
46
+
47
+ class PaginatedResponse(BaseModel, Generic[T]):
48
+ """Generic paginated response."""
49
+
50
+ items: List[T]
51
+ total: int
52
+ page: int
53
+ page_size: int
54
+ pages: int
55
+
56
+
57
+ # Request/Response models
58
+ class UserSummary(BaseModel):
59
+ """Summary information about a user."""
60
+
61
+ user_id: str
62
+ username: str
63
+ auth_type: str = Field(description="password, oauth, api_key")
64
+ api_role: APIRole
65
+ wa_role: Optional[WARole] = None
66
+ wa_id: Optional[str] = None
67
+ oauth_provider: Optional[str] = None
68
+ oauth_email: Optional[str] = None
69
+ oauth_name: Optional[str] = None # Full name from OAuth provider
70
+ oauth_picture: Optional[str] = None # Profile picture URL
71
+ permission_requested_at: Optional[datetime] = None # Permission request timestamp
72
+ created_at: datetime
73
+ last_login: Optional[datetime] = None
74
+ is_active: bool = True
75
+ linked_oauth_accounts: List["LinkedOAuthAccount"] = Field(default_factory=list)
76
+
77
+
78
+ class UserDetail(UserSummary):
79
+ """Detailed user information."""
80
+
81
+ permissions: List[str]
82
+ custom_permissions: Optional[List[str]] = None
83
+ oauth_external_id: Optional[str] = None
84
+ wa_parent_id: Optional[str] = None
85
+ wa_auto_minted: bool = False
86
+ api_keys_count: int = 0
87
+
88
+
89
+ class LinkedOAuthAccount(BaseModel):
90
+ """Linked OAuth identity summary."""
91
+
92
+ provider: str
93
+ external_id: str
94
+ account_name: Optional[str] = None
95
+ linked_at: Optional[datetime] = None
96
+ is_primary: bool = False
97
+ metadata: Dict[str, str] = Field(default_factory=dict)
98
+
99
+
100
+ def _build_linked_accounts(user: Any) -> List[LinkedOAuthAccount]:
101
+ accounts: List[LinkedOAuthAccount] = []
102
+ seen = set()
103
+
104
+ for link in getattr(user, "oauth_links", []) or []:
105
+ key = (link.provider, link.external_id)
106
+ seen.add(key)
107
+ accounts.append(
108
+ LinkedOAuthAccount(
109
+ provider=link.provider,
110
+ external_id=link.external_id,
111
+ account_name=getattr(link, "account_name", None),
112
+ linked_at=getattr(link, "linked_at", None),
113
+ is_primary=getattr(link, "is_primary", False),
114
+ metadata=getattr(link, "metadata", {}) or {},
115
+ )
116
+ )
117
+
118
+ if user.oauth_provider and user.oauth_external_id:
119
+ key = (user.oauth_provider, user.oauth_external_id)
120
+ if key not in seen:
121
+ accounts.append(
122
+ LinkedOAuthAccount(
123
+ provider=user.oauth_provider,
124
+ external_id=user.oauth_external_id,
125
+ account_name=getattr(user, "oauth_name", None),
126
+ linked_at=None,
127
+ is_primary=True,
128
+ metadata={},
129
+ )
130
+ )
131
+
132
+ primary_found = False
133
+ for account in accounts:
134
+ if account.is_primary and not primary_found:
135
+ primary_found = True
136
+ else:
137
+ account.is_primary = account.is_primary and primary_found
138
+
139
+ if accounts and not any(account.is_primary for account in accounts):
140
+ accounts[0].is_primary = True
141
+
142
+ return accounts
143
+
144
+
145
+ def _build_user_detail(user_id: str, user: Any, auth_service: APIAuthService) -> UserDetail:
146
+ """Build UserDetail response from user object (DRY helper)."""
147
+ # Use effective permissions which includes WA role inheritance
148
+ # ROOT WA users get AUTHORITY permissions (including wa.resolve_deferral)
149
+ permissions = auth_service.get_effective_permissions(user)
150
+ api_keys = auth_service.list_user_api_keys(user_id)
151
+
152
+ return UserDetail(
153
+ user_id=user_id,
154
+ username=user.name,
155
+ auth_type=user.auth_type,
156
+ api_role=user.api_role,
157
+ wa_role=user.wa_role,
158
+ wa_id=user.wa_id if user.wa_role else None,
159
+ oauth_provider=user.oauth_provider,
160
+ oauth_email=user.oauth_email,
161
+ oauth_name=user.oauth_name,
162
+ oauth_picture=user.oauth_picture,
163
+ permission_requested_at=user.permission_requested_at,
164
+ oauth_external_id=user.oauth_external_id,
165
+ created_at=user.created_at,
166
+ last_login=user.last_login,
167
+ is_active=user.is_active,
168
+ permissions=permissions,
169
+ custom_permissions=user.custom_permissions,
170
+ wa_parent_id=user.wa_parent_id,
171
+ wa_auto_minted=user.wa_auto_minted,
172
+ api_keys_count=len(api_keys),
173
+ linked_oauth_accounts=_build_linked_accounts(user),
174
+ )
175
+
176
+
177
+ class UpdateUserRequest(BaseModel):
178
+ """Request to update user information."""
179
+
180
+ api_role: Optional[APIRole] = None
181
+ is_active: Optional[bool] = None
182
+
183
+
184
+ class ChangePasswordRequest(BaseModel):
185
+ """Request to change user password."""
186
+
187
+ current_password: str
188
+ new_password: str
189
+
190
+
191
+ class LinkOAuthAccountRequest(BaseModel):
192
+ """Request payload to link an OAuth account to a user."""
193
+
194
+ provider: str = Field(..., description="OAuth provider identifier")
195
+ external_id: str = Field(..., description="Provider-scoped user identifier")
196
+ account_name: Optional[str] = Field(None, description="Display name provided by the provider")
197
+ metadata: Dict[str, str] = Field(default_factory=dict, description="Additional metadata from the provider")
198
+ primary: bool = Field(False, description="Promote this identity to the primary mapping")
199
+
200
+
201
+ class CreateUserRequest(BaseModel):
202
+ """Request to create a new user."""
203
+
204
+ username: str = Field(..., min_length=3, max_length=50)
205
+ password: str = Field(..., min_length=8)
206
+ api_role: APIRole = APIRole.OBSERVER
207
+
208
+
209
+ class MintWARequest(BaseModel):
210
+ """Request to mint user as Wise Authority."""
211
+
212
+ model_config = ConfigDict(
213
+ json_schema_extra={"example": {"wa_role": "AUTHORITY", "signature": "base64_encoded_signature"}}
214
+ )
215
+
216
+ wa_role: WARole = Field(description="Role to grant: AUTHORITY or OBSERVER")
217
+ signature: Optional[str] = Field(None, description="Ed25519 signature from ROOT private key")
218
+ private_key_path: Optional[str] = Field(None, description="Path to ROOT private key for auto-signing")
219
+
220
+
221
+ class UpdatePermissionsRequest(BaseModel):
222
+ """Request to update user's custom permissions."""
223
+
224
+ model_config = ConfigDict(json_schema_extra={"example": {"permissions": ["send_messages", "custom_permission_1"]}})
225
+
226
+ permissions: List[str] = Field(description="List of permission strings to grant")
227
+
228
+
229
+ class WAKeyCheckResponse(BaseModel):
230
+ """Response for WA key existence check."""
231
+
232
+ exists: bool = Field(..., description="Whether the key file exists")
233
+ filename: str = Field(..., description="The filename that was checked")
234
+ error: Optional[str] = Field(None, description="Error message if any")
235
+ valid_size: Optional[bool] = Field(None, description="Whether the key has valid size (if exists)")
236
+ size: Optional[int] = Field(None, description="File size in bytes (if exists)")
237
+
238
+
239
+ class DeactivateUserResponse(BaseModel):
240
+ """Response for user deactivation."""
241
+
242
+ message: str = Field(..., description="Success message")
243
+
244
+
245
+ class APIKeyInfo(BaseModel):
246
+ """Information about an API key (masked for security)."""
247
+
248
+ key_id: str = Field(..., description="Unique key identifier")
249
+ masked_key: str = Field(..., description="Masked version of the key (e.g., 'ciris_****')")
250
+ created_at: datetime = Field(..., description="When the key was created")
251
+ last_used: Optional[datetime] = Field(None, description="When the key was last used")
252
+ is_active: bool = Field(..., description="Whether the key is currently active")
253
+ name: Optional[str] = Field(None, description="Optional name for the key")
254
+
255
+
256
+ class UserSettingsResponse(BaseModel):
257
+ """User's personal settings (user-modifiable preferences)."""
258
+
259
+ user_preferred_name: Optional[str] = Field(None, description="User's preferred display name")
260
+ location: Optional[str] = Field(None, description="User's location preference")
261
+ interaction_preferences: Optional[str] = Field(None, description="User's custom interaction preferences")
262
+ marketing_opt_in: bool = Field(False, description="User consent for marketing communications")
263
+ marketing_opt_in_source: Optional[str] = Field(None, description="Source of marketing consent (read-only)")
264
+
265
+
266
+ class UpdateUserSettingsRequest(BaseModel):
267
+ """Request to update user's personal settings."""
268
+
269
+ user_preferred_name: Optional[str] = Field(None, description="User's preferred display name")
270
+ location: Optional[str] = Field(None, description="User's location preference")
271
+ interaction_preferences: Optional[str] = Field(None, description="User's custom interaction preferences")
272
+ marketing_opt_in: Optional[bool] = Field(None, description="User consent for marketing communications")
273
+
274
+
275
+ @router.get("", response_model=PaginatedResponse[UserSummary])
276
+ async def list_users(
277
+ page: int = Query(1, ge=1),
278
+ page_size: int = Query(20, ge=1, le=100),
279
+ search: Optional[str] = None,
280
+ auth_type: Optional[str] = None,
281
+ api_role: Optional[APIRole] = None,
282
+ wa_role: Optional[WARole] = None,
283
+ is_active: Optional[bool] = None,
284
+ auth: AuthContext = Depends(get_auth_context),
285
+ auth_service: APIAuthService = Depends(get_auth_service),
286
+ _: None = Depends(check_permissions([PERMISSION_USERS_READ])),
287
+ ) -> PaginatedResponse[UserSummary]:
288
+ """
289
+ List all users with optional filtering.
290
+
291
+ Requires: users.read permission (ADMIN or higher)
292
+ """
293
+ # Get all WA certificates from the auth service
294
+ users = await auth_service.list_users(
295
+ search=search, auth_type=auth_type, api_role=api_role, wa_role=wa_role, is_active=is_active
296
+ )
297
+
298
+ # Paginate results
299
+ total = len(users)
300
+ start = (page - 1) * page_size
301
+ end = start + page_size
302
+
303
+ # Convert to UserSummary objects
304
+ items = []
305
+ for user_id, user in users[start:end]:
306
+ items.append(
307
+ UserSummary(
308
+ user_id=user_id, # Use the actual user_id key, not wa_id
309
+ username=user.name,
310
+ auth_type=user.auth_type,
311
+ api_role=user.api_role,
312
+ wa_role=user.wa_role,
313
+ wa_id=user.wa_id if user.wa_role else None,
314
+ oauth_provider=user.oauth_provider,
315
+ oauth_email=user.oauth_email,
316
+ oauth_name=user.oauth_name,
317
+ oauth_picture=user.oauth_picture,
318
+ permission_requested_at=user.permission_requested_at,
319
+ created_at=user.created_at,
320
+ last_login=user.last_login,
321
+ is_active=user.is_active,
322
+ linked_oauth_accounts=_build_linked_accounts(user),
323
+ )
324
+ )
325
+
326
+ return PaginatedResponse(
327
+ items=items, total=total, page=page, page_size=page_size, pages=(total + page_size - 1) // page_size
328
+ )
329
+
330
+
331
+ @router.post("", response_model=UserDetail)
332
+ async def create_user(
333
+ request: CreateUserRequest,
334
+ auth: AuthContext = Depends(get_auth_context),
335
+ auth_service: APIAuthService = Depends(get_auth_service),
336
+ _: None = Depends(check_permissions([PERMISSION_USERS_WRITE])),
337
+ ) -> UserDetail:
338
+ """
339
+ Create a new user account.
340
+
341
+ Requires: users.write permission (SYSTEM_ADMIN only)
342
+ """
343
+ # Check if username already exists
344
+ existing = auth_service.get_user_by_username(request.username)
345
+ if existing:
346
+ raise HTTPException(status_code=400, detail=ERROR_USERNAME_EXISTS)
347
+
348
+ # Create the user
349
+ user = await auth_service.create_user(
350
+ username=request.username, password=request.password, api_role=request.api_role
351
+ )
352
+
353
+ if not user:
354
+ raise HTTPException(status_code=500, detail=ERROR_CREATE_USER_FAILED)
355
+
356
+ # Return the created user details
357
+ return await get_user(user.wa_id, auth, auth_service, None)
358
+
359
+
360
+ @router.post("/request-permissions", response_model=PermissionRequestResponse)
361
+ async def request_permissions(
362
+ auth: AuthContext = Depends(get_auth_context), auth_service: APIAuthService = Depends(get_auth_service)
363
+ ) -> PermissionRequestResponse:
364
+ """
365
+ Request communication permissions for the current user.
366
+
367
+ Requires: Must be authenticated (any role)
368
+ """
369
+ from ciris_engine.schemas.api.auth import Permission, PermissionRequestResponse
370
+
371
+ # Check if user already has SEND_MESSAGES permission
372
+ if auth.has_permission(Permission.SEND_MESSAGES):
373
+ return PermissionRequestResponse(
374
+ success=True, status="already_granted", message="You already have communication permissions."
375
+ )
376
+
377
+ # Get the current user
378
+ user = auth_service.get_user(auth.user_id)
379
+ if not user:
380
+ raise HTTPException(status_code=404, detail=ERROR_USER_NOT_FOUND)
381
+
382
+ # Check if request already pending
383
+ if user.permission_requested_at:
384
+ return PermissionRequestResponse(
385
+ success=True,
386
+ status="already_requested",
387
+ message="Your permission request is pending review.",
388
+ requested_at=user.permission_requested_at,
389
+ )
390
+
391
+ # Set permission request timestamp
392
+ user.permission_requested_at = datetime.now()
393
+ # Store the updated user
394
+ auth_service._users[user.wa_id] = user
395
+
396
+ logger.info(f"Permission request submitted by user ID: {user.wa_id}")
397
+
398
+ return PermissionRequestResponse(
399
+ success=True,
400
+ status="request_submitted",
401
+ message="Your request has been submitted for review.",
402
+ requested_at=user.permission_requested_at,
403
+ )
404
+
405
+
406
+ @router.get("/permission-requests", response_model=List[PermissionRequestUser])
407
+ async def get_permission_requests(
408
+ auth: AuthContext = Depends(get_auth_context),
409
+ auth_service: APIAuthService = Depends(get_auth_service),
410
+ include_granted: bool = Query(False, description="Include users who already have permissions"),
411
+ ) -> List[PermissionRequestUser]:
412
+ """
413
+ Get list of users who have requested permissions.
414
+
415
+ Requires: ADMIN role or higher
416
+ """
417
+ from ciris_engine.schemas.api.auth import Permission, PermissionRequestUser
418
+
419
+ logger.info(f"Permission requests called by {auth.user_id} with role {auth.role}")
420
+
421
+ # Check permissions - require ADMIN or higher
422
+ if auth.role not in [UserRole.ADMIN, UserRole.AUTHORITY, UserRole.SYSTEM_ADMIN]:
423
+ logger.error(f"Insufficient permissions for user {auth.user_id} with role {auth.role}")
424
+ raise HTTPException(status_code=403, detail="Insufficient permissions")
425
+
426
+ permission_requests = []
427
+
428
+ # Check all users for permission requests
429
+ logger.info(f"Checking {len(auth_service._users)} users in _users dict")
430
+ for user_id, user in auth_service._users.items():
431
+ # Skip users without permission requests
432
+ if not user.permission_requested_at:
433
+ continue
434
+
435
+ # Check if user has SEND_MESSAGES permission
436
+ has_send_messages = Permission.SEND_MESSAGES.value in (user.custom_permissions or [])
437
+
438
+ # Skip users who already have permissions unless include_granted is True
439
+ if has_send_messages and not include_granted:
440
+ continue
441
+
442
+ # Add to results
443
+ permission_requests.append(
444
+ PermissionRequestUser(
445
+ id=user.wa_id,
446
+ email=user.oauth_email,
447
+ oauth_name=user.oauth_name,
448
+ oauth_picture=user.oauth_picture,
449
+ role=UserRole.OBSERVER, # OAuth users are always OBSERVER initially
450
+ permission_requested_at=user.permission_requested_at,
451
+ has_send_messages=has_send_messages,
452
+ )
453
+ )
454
+
455
+ # Sort by request date (newest first)
456
+ permission_requests.sort(key=lambda x: x.permission_requested_at, reverse=True)
457
+
458
+ return permission_requests
459
+
460
+
461
+ @router.get("/me/settings", response_model=UserSettingsResponse)
462
+ async def get_my_settings(
463
+ request: Request,
464
+ auth: AuthContext = Depends(get_auth_context),
465
+ ) -> UserSettingsResponse:
466
+ """
467
+ Get the current user's personal settings.
468
+
469
+ Requires: Must be authenticated (any role)
470
+ """
471
+ from ciris_engine.schemas.services.graph_core import GraphScope, NodeType
472
+ from ciris_engine.schemas.services.operations import MemoryQuery
473
+
474
+ # Get the memory service from app state
475
+ memory_service = getattr(request.app.state, "memory_service", None)
476
+ if not memory_service:
477
+ raise HTTPException(status_code=503, detail="Memory service not available")
478
+
479
+ try:
480
+ # Query the user node from the graph
481
+ user_query = MemoryQuery(
482
+ node_id=f"user/{auth.user_id}",
483
+ scope=GraphScope.LOCAL,
484
+ type=NodeType.USER,
485
+ include_edges=False,
486
+ depth=1,
487
+ )
488
+ user_results = await memory_service.recall(user_query)
489
+
490
+ if not user_results:
491
+ # User node doesn't exist yet - return defaults
492
+ return UserSettingsResponse()
493
+
494
+ user_node = user_results[0]
495
+ attrs = user_node.attributes if isinstance(user_node.attributes, dict) else {}
496
+
497
+ # Extract user settings from node attributes
498
+ return UserSettingsResponse(
499
+ user_preferred_name=attrs.get("user_preferred_name"),
500
+ location=attrs.get("location"),
501
+ interaction_preferences=attrs.get("interaction_preferences"),
502
+ marketing_opt_in=attrs.get("marketing_opt_in", False),
503
+ marketing_opt_in_source=attrs.get("marketing_opt_in_source"),
504
+ )
505
+
506
+ except Exception as e:
507
+ logger.error(f"Failed to retrieve user settings for {auth.user_id}: {e}")
508
+ raise HTTPException(status_code=500, detail="Failed to retrieve user settings")
509
+
510
+
511
+ @router.put("/me/settings", response_model=UserSettingsResponse)
512
+ async def update_my_settings(
513
+ http_request: Request,
514
+ request: UpdateUserSettingsRequest,
515
+ auth: AuthContext = Depends(get_auth_context),
516
+ ) -> UserSettingsResponse:
517
+ """
518
+ Update the current user's personal settings.
519
+
520
+ Requires: Must be authenticated (any role)
521
+
522
+ Note: This endpoint bypasses the MANAGED_USER_ATTRIBUTES protection
523
+ because users are allowed to modify their own settings.
524
+ """
525
+ from ciris_engine.schemas.services.graph_core import GraphNode, GraphScope, NodeType
526
+ from ciris_engine.schemas.services.operations import MemoryQuery
527
+
528
+ # Get the memory service from app state
529
+ memory_service = getattr(http_request.app.state, "memory_service", None)
530
+ if not memory_service:
531
+ raise HTTPException(status_code=503, detail="Memory service not available")
532
+
533
+ try:
534
+ # Query the user node from the graph
535
+ user_query = MemoryQuery(
536
+ node_id=f"user/{auth.user_id}",
537
+ scope=GraphScope.LOCAL,
538
+ type=NodeType.USER,
539
+ include_edges=False,
540
+ depth=1,
541
+ )
542
+ user_results = await memory_service.recall(user_query)
543
+
544
+ # Prepare attributes to update (only include fields that were provided)
545
+ attrs_to_update: JSONDict = {}
546
+ if request.user_preferred_name is not None:
547
+ attrs_to_update["user_preferred_name"] = request.user_preferred_name
548
+ if request.location is not None:
549
+ attrs_to_update["location"] = request.location
550
+ if request.interaction_preferences is not None:
551
+ attrs_to_update["interaction_preferences"] = request.interaction_preferences
552
+ if request.marketing_opt_in is not None:
553
+ attrs_to_update["marketing_opt_in"] = request.marketing_opt_in
554
+ # Update marketing_opt_in_source when user changes their preference
555
+ attrs_to_update["marketing_opt_in_source"] = "settings_api"
556
+
557
+ if user_results:
558
+ # User node exists - update it
559
+ user_node = user_results[0]
560
+ existing_attrs = user_node.attributes if isinstance(user_node.attributes, dict) else {}
561
+
562
+ # Merge existing attributes with updates
563
+ updated_attrs = {**existing_attrs, **attrs_to_update}
564
+
565
+ # Create updated node
566
+ updated_node = GraphNode(
567
+ id=f"user/{auth.user_id}",
568
+ type=NodeType.USER,
569
+ scope=GraphScope.LOCAL,
570
+ attributes=updated_attrs,
571
+ )
572
+
573
+ # Save the updated node directly (bypassing MANAGED_USER_ATTRIBUTES check)
574
+ await memory_service.memorize(updated_node, handler_name="UserSettingsAPI")
575
+
576
+ else:
577
+ # User node doesn't exist - create it with the settings
578
+ new_node = GraphNode(
579
+ id=f"user/{auth.user_id}",
580
+ type=NodeType.USER,
581
+ scope=GraphScope.LOCAL,
582
+ attributes=attrs_to_update,
583
+ )
584
+
585
+ # Save the new node
586
+ await memory_service.memorize(new_node, handler_name="UserSettingsAPI")
587
+
588
+ # Return the updated settings
589
+ final_attrs = {**attrs_to_update}
590
+ if user_results:
591
+ user_node = user_results[0]
592
+ existing_attrs = user_node.attributes if isinstance(user_node.attributes, dict) else {}
593
+ final_attrs = {**existing_attrs, **attrs_to_update}
594
+
595
+ return UserSettingsResponse(
596
+ user_preferred_name=final_attrs.get("user_preferred_name"),
597
+ location=final_attrs.get("location"),
598
+ interaction_preferences=final_attrs.get("interaction_preferences"),
599
+ marketing_opt_in=final_attrs.get("marketing_opt_in", False),
600
+ marketing_opt_in_source=final_attrs.get("marketing_opt_in_source"),
601
+ )
602
+
603
+ except Exception as e:
604
+ logger.error(f"Failed to update user settings for {auth.user_id}: {e}")
605
+ raise HTTPException(status_code=500, detail="Failed to update user settings")
606
+
607
+
608
+ @router.get("/{user_id}", response_model=UserDetail)
609
+ async def get_user(
610
+ user_id: str,
611
+ auth: AuthContext = Depends(get_auth_context),
612
+ auth_service: APIAuthService = Depends(get_auth_service),
613
+ _: None = Depends(check_permissions([PERMISSION_USERS_READ])),
614
+ ) -> UserDetail:
615
+ """
616
+ Get detailed information about a specific user.
617
+
618
+ Requires: users.read permission (ADMIN or higher)
619
+ """
620
+ user = auth_service.get_user(user_id)
621
+ if not user:
622
+ raise HTTPException(status_code=404, detail=ERROR_USER_NOT_FOUND)
623
+
624
+ return _build_user_detail(user_id, user, auth_service)
625
+
626
+
627
+ @router.put("/{user_id}", response_model=UserDetail)
628
+ async def update_user(
629
+ user_id: str,
630
+ request: UpdateUserRequest,
631
+ auth: AuthContext = Depends(get_auth_context),
632
+ auth_service: APIAuthService = Depends(get_auth_service),
633
+ _: None = Depends(check_permissions([PERMISSION_USERS_WRITE])),
634
+ ) -> UserDetail:
635
+ """
636
+ Update user information (role, active status).
637
+
638
+ Requires: users.write permission (SYSTEM_ADMIN only)
639
+ """
640
+ # Prevent self-demotion
641
+ if user_id == auth.user_id and request.api_role:
642
+ if request.api_role.value < auth.role.value:
643
+ raise HTTPException(status_code=400, detail=ERROR_CANNOT_DEMOTE_SELF)
644
+
645
+ # Update user
646
+ user = await auth_service.update_user(user_id=user_id, api_role=request.api_role, is_active=request.is_active)
647
+
648
+ if not user:
649
+ raise HTTPException(status_code=404, detail=ERROR_USER_NOT_FOUND)
650
+
651
+ # Return updated user details
652
+ return await get_user(user_id, auth, auth_service, None)
653
+
654
+
655
+ @router.put("/{user_id}/password")
656
+ async def change_password(
657
+ user_id: str,
658
+ request: ChangePasswordRequest,
659
+ auth: AuthContext = Depends(get_auth_context),
660
+ auth_service: APIAuthService = Depends(get_auth_service),
661
+ ) -> Dict[str, str]:
662
+ """
663
+ Change user password.
664
+
665
+ Users can change their own password.
666
+ SYSTEM_ADMIN can change any password without knowing current.
667
+ """
668
+ # Check permissions
669
+ if user_id != auth.user_id:
670
+ # Only SYSTEM_ADMIN can change other users' passwords
671
+ await check_permissions([PERMISSION_USERS_WRITE])(auth, auth_service)
672
+ # SYSTEM_ADMIN doesn't need to provide current password
673
+ success = await auth_service.change_password(
674
+ user_id=user_id, new_password=request.new_password, skip_current_check=True
675
+ )
676
+ else:
677
+ # Users changing their own password must provide current
678
+ success = await auth_service.change_password(
679
+ user_id=user_id, new_password=request.new_password, current_password=request.current_password
680
+ )
681
+
682
+ if not success:
683
+ raise HTTPException(status_code=400, detail=ERROR_CHANGE_PASSWORD_FAILED)
684
+
685
+ return {"message": "Password changed successfully"}
686
+
687
+
688
+ @router.post("/{user_id}/oauth-links", response_model=UserDetail)
689
+ async def link_oauth_account(
690
+ user_id: str,
691
+ request: LinkOAuthAccountRequest,
692
+ auth: AuthContext = Depends(get_auth_context),
693
+ auth_service: APIAuthService = Depends(get_auth_service),
694
+ ) -> UserDetail:
695
+ """
696
+ Link an OAuth identity to an existing user.
697
+
698
+ Users can link accounts to themselves without special permissions.
699
+ Only SYSTEM_ADMIN can link accounts to other users.
700
+ """
701
+ # Check permissions: users can link to their own account, SYSTEM_ADMIN can link to any
702
+ if user_id != auth.user_id:
703
+ await check_permissions([PERMISSION_USERS_WRITE])(auth, auth_service)
704
+
705
+ user = await auth_service.link_user_oauth(
706
+ wa_id=user_id,
707
+ provider=request.provider,
708
+ external_id=request.external_id,
709
+ account_name=request.account_name,
710
+ metadata=request.metadata,
711
+ primary=request.primary,
712
+ )
713
+
714
+ if not user:
715
+ raise HTTPException(status_code=404, detail=ERROR_USER_NOT_FOUND)
716
+
717
+ return _build_user_detail(user_id, user, auth_service)
718
+
719
+
720
+ @router.delete("/{user_id}/oauth-links/{provider}/{external_id}", response_model=UserDetail)
721
+ async def unlink_oauth_account(
722
+ user_id: str,
723
+ provider: str,
724
+ external_id: str,
725
+ auth: AuthContext = Depends(get_auth_context),
726
+ auth_service: APIAuthService = Depends(get_auth_service),
727
+ ) -> UserDetail:
728
+ """
729
+ Remove a linked OAuth identity from a user.
730
+
731
+ Users can unlink accounts from themselves without special permissions.
732
+ Only SYSTEM_ADMIN can unlink accounts from other users.
733
+ """
734
+ # Check permissions: users can unlink from their own account, SYSTEM_ADMIN can unlink from any
735
+ if user_id != auth.user_id:
736
+ await check_permissions([PERMISSION_USERS_WRITE])(auth, auth_service)
737
+
738
+ user = await auth_service.unlink_user_oauth(user_id, provider, external_id)
739
+ if not user:
740
+ raise HTTPException(status_code=404, detail=ERROR_USER_NOT_FOUND)
741
+
742
+ return _build_user_detail(user_id, user, auth_service)
743
+
744
+
745
+ @router.post("/{user_id}/mint-wa", response_model=UserDetail)
746
+ async def mint_wise_authority(
747
+ user_id: str,
748
+ request: MintWARequest,
749
+ auth: AuthContext = Depends(get_auth_context),
750
+ auth_service: APIAuthService = Depends(get_auth_service),
751
+ ) -> UserDetail:
752
+ """
753
+ Mint a user as a Wise Authority.
754
+
755
+ Requires: ADMIN role or higher and valid Ed25519 signature from ROOT private key.
756
+
757
+ The signature should be over the message:
758
+ "MINT_WA:{user_id}:{wa_role}:{timestamp}"
759
+
760
+ If no signature is provided and private_key_path is specified, will attempt
761
+ to sign automatically using the key at that path.
762
+ """
763
+ # Check if user is ADMIN or higher
764
+ if auth.role.level < APIRole.ADMIN.level:
765
+ raise HTTPException(status_code=403, detail=ERROR_ONLY_ADMIN_MINT_WA)
766
+
767
+ # Validate that request.wa_role is not ROOT
768
+ if request.wa_role == WARole.ROOT:
769
+ raise HTTPException(status_code=400, detail=ERROR_CANNOT_MINT_ROOT)
770
+
771
+ # If no signature provided but private key path is given, try to auto-sign
772
+ signature = request.signature
773
+ if not signature and request.private_key_path:
774
+ # Auto-sign using the provided private key
775
+ import base64
776
+ import os
777
+
778
+ from cryptography.hazmat.primitives.asymmetric import ed25519
779
+
780
+ try:
781
+ # Security: Validate the private key path
782
+ # Only allow alphanumeric characters, dots, dashes, and underscores in filename
783
+ import re
784
+
785
+ if not request.private_key_path:
786
+ raise HTTPException(status_code=400, detail="Private key path is required")
787
+
788
+ # Extract just the filename, no path components allowed
789
+ filename = os.path.basename(request.private_key_path)
790
+ if not re.match(r"^[a-zA-Z0-9._-]+$", filename):
791
+ raise HTTPException(
792
+ status_code=400,
793
+ detail="Invalid key filename. Only alphanumeric characters, dots, dashes, and underscores are allowed",
794
+ )
795
+
796
+ # Construct the safe path - no user input in directory path
797
+ allowed_base = os.path.expanduser("~/.ciris/wa_keys/")
798
+ safe_path = os.path.join(allowed_base, filename)
799
+
800
+ # Double-check with realpath to prevent any symlink attacks
801
+ resolved_path = os.path.realpath(safe_path)
802
+ allowed_base_resolved = os.path.realpath(allowed_base)
803
+ if not resolved_path.startswith(allowed_base_resolved):
804
+ raise HTTPException(status_code=403, detail="Access denied: path traversal detected")
805
+
806
+ # Read the private key
807
+ async with aiofiles.open(resolved_path, "rb") as f:
808
+ private_key_bytes = await f.read()
809
+
810
+ # Create Ed25519 private key object
811
+ private_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_key_bytes)
812
+
813
+ # Sign the message
814
+ message = f"MINT_WA:{user_id}:{request.wa_role.value}"
815
+ signature_bytes = private_key.sign(message.encode())
816
+
817
+ # Encode to base64
818
+ signature = base64.b64encode(signature_bytes).decode()
819
+
820
+ logger.info(f"Auto-signed WA mint request for {user_id} using key file: {filename}")
821
+
822
+ except FileNotFoundError:
823
+ raise HTTPException(status_code=404, detail=f"Private key file not found: {filename}")
824
+ except Exception as e:
825
+ logger.error(f"Failed to auto-sign: {e}")
826
+ raise HTTPException(status_code=500, detail="Failed to auto-sign with provided private key")
827
+
828
+ if not signature:
829
+ raise HTTPException(status_code=400, detail=ERROR_SIGNATURE_OR_KEY_REQUIRED)
830
+
831
+ # Verify the ROOT signature
832
+ verified = await auth_service.verify_root_signature(user_id=user_id, wa_role=request.wa_role, signature=signature)
833
+
834
+ if not verified:
835
+ raise HTTPException(status_code=401, detail=ERROR_INVALID_SIGNATURE)
836
+
837
+ # Mint the user as WA
838
+ user = await auth_service.mint_wise_authority(user_id=user_id, wa_role=request.wa_role, minted_by=auth.user_id)
839
+
840
+ if not user:
841
+ raise HTTPException(status_code=404, detail=ERROR_USER_NOT_FOUND)
842
+
843
+ # Return updated user details
844
+ return await get_user(user_id, auth, auth_service, None)
845
+
846
+
847
+ @router.get("/wa/key-check", response_model=WAKeyCheckResponse)
848
+ async def check_wa_key_exists(
849
+ path: str = Query(..., description="Filename of private key to check"),
850
+ auth: AuthContext = Depends(get_auth_context),
851
+ _: None = Depends(check_permissions([PERMISSION_WA_MINT])), # SYSTEM_ADMIN only
852
+ ) -> WAKeyCheckResponse:
853
+ """
854
+ Check if a WA private key exists at the given filename.
855
+
856
+ Requires: wa.mint permission (SYSTEM_ADMIN only)
857
+
858
+ This is used by the UI to determine if auto-signing is available.
859
+ Only checks files within ~/.ciris/wa_keys/ for security.
860
+ """
861
+ import os
862
+ import re
863
+
864
+ try:
865
+ # Security: Validate the filename
866
+ # Extract just the filename, no path components allowed
867
+ filename = os.path.basename(path)
868
+ if not re.match(r"^[a-zA-Z0-9._-]+$", filename):
869
+ return WAKeyCheckResponse(
870
+ exists=False,
871
+ filename=filename,
872
+ error="Invalid filename. Only alphanumeric characters, dots, dashes, and underscores are allowed",
873
+ )
874
+
875
+ # Construct the safe path - no user input in directory path
876
+ allowed_base = os.path.expanduser("~/.ciris/wa_keys/")
877
+ safe_path = os.path.join(allowed_base, filename)
878
+
879
+ # Double-check with realpath to prevent any symlink attacks
880
+ resolved_path = os.path.realpath(safe_path)
881
+ allowed_base_resolved = os.path.realpath(allowed_base)
882
+ if not resolved_path.startswith(allowed_base_resolved):
883
+ return WAKeyCheckResponse(exists=False, filename=filename, error="Access denied: path traversal detected")
884
+
885
+ # Check if file exists and is readable
886
+ exists = os.path.isfile(resolved_path) and os.access(resolved_path, os.R_OK)
887
+
888
+ # If exists, check if it's a valid key size (32 bytes for Ed25519)
889
+ if exists:
890
+ file_size = os.path.getsize(resolved_path)
891
+ valid_size = file_size == 32 # Ed25519 private key is 32 bytes
892
+
893
+ return WAKeyCheckResponse(exists=True, valid_size=valid_size, size=file_size, filename=filename)
894
+ else:
895
+ return WAKeyCheckResponse(exists=False, filename=filename)
896
+
897
+ except Exception as e:
898
+ logger.error(f"Error checking key file {filename}: {e}")
899
+ return WAKeyCheckResponse(exists=False, error="Failed to check key file", filename=filename)
900
+
901
+
902
+ @router.delete("/{user_id}", response_model=DeactivateUserResponse)
903
+ async def deactivate_user(
904
+ user_id: str,
905
+ auth: AuthContext = Depends(get_auth_context),
906
+ auth_service: APIAuthService = Depends(get_auth_service),
907
+ _: None = Depends(check_permissions([PERMISSION_USERS_DELETE])),
908
+ ) -> DeactivateUserResponse:
909
+ """
910
+ Deactivate a user account.
911
+
912
+ Requires: users.delete permission (SYSTEM_ADMIN only)
913
+ """
914
+ # Prevent self-deactivation
915
+ if user_id == auth.user_id:
916
+ raise HTTPException(status_code=400, detail=ERROR_CANNOT_DEACTIVATE_SELF)
917
+
918
+ success = await auth_service.deactivate_user(user_id)
919
+
920
+ if not success:
921
+ raise HTTPException(status_code=404, detail=ERROR_USER_NOT_FOUND)
922
+
923
+ return DeactivateUserResponse(message="User deactivated successfully")
924
+
925
+
926
+ @router.get("/{user_id}/api-keys", response_model=List[APIKeyInfo])
927
+ async def list_user_api_keys(
928
+ user_id: str,
929
+ auth: AuthContext = Depends(get_auth_context),
930
+ auth_service: APIAuthService = Depends(get_auth_service),
931
+ ) -> List[APIKeyInfo]:
932
+ """
933
+ List API keys for a user.
934
+
935
+ Users can view their own keys.
936
+ ADMIN+ can view any user's keys.
937
+ """
938
+ # Check permissions
939
+ if user_id != auth.user_id:
940
+ await check_permissions([PERMISSION_USERS_READ])(auth, auth_service)
941
+
942
+ keys = auth_service.list_user_api_keys(user_id)
943
+
944
+ # Mask the actual key values for security
945
+ return [
946
+ APIKeyInfo(
947
+ key_id=key.key_id,
948
+ masked_key=key.key_value[:8] + "****" if len(key.key_value) > 8 else "****",
949
+ created_at=key.created_at,
950
+ last_used=key.last_used,
951
+ is_active=key.is_active,
952
+ name=getattr(key, "name", None),
953
+ )
954
+ for key in keys
955
+ ]
956
+
957
+
958
+ @router.put("/{user_id}/permissions", response_model=UserDetail)
959
+ async def update_user_permissions(
960
+ user_id: str,
961
+ request: UpdatePermissionsRequest,
962
+ auth: AuthContext = Depends(get_auth_context),
963
+ auth_service: APIAuthService = Depends(get_auth_service),
964
+ _: None = Depends(check_permissions([PERMISSION_MANAGE_USER_PERMISSIONS])),
965
+ ) -> UserDetail:
966
+ """
967
+ Update user's custom permissions.
968
+
969
+ Requires: users.permissions permission (AUTHORITY or higher)
970
+
971
+ This allows granting specific permissions to users beyond their role defaults.
972
+ For example, granting SEND_MESSAGES permission to an OBSERVER.
973
+ """
974
+ # Update user permissions
975
+ user = await auth_service.update_user_permissions(user_id=user_id, permissions=request.permissions)
976
+
977
+ if not user:
978
+ raise HTTPException(status_code=404, detail=ERROR_USER_NOT_FOUND)
979
+
980
+ # Return updated user details
981
+ return await get_user(user_id, auth, auth_service, None)