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,1374 @@
1
+ """
2
+ Setup wizard endpoints for CIRIS first-run and reconfiguration.
3
+
4
+ Provides GUI-based setup wizard accessible at /v1/setup/*.
5
+ Replaces the CLI wizard for pip-installed CIRIS agents.
6
+ """
7
+
8
+ import json
9
+ import logging
10
+ import os
11
+ import secrets
12
+ import time
13
+ from datetime import datetime, timezone
14
+ from pathlib import Path
15
+ from typing import Any, Dict, List, Optional
16
+
17
+ from fastapi import APIRouter, Depends, HTTPException, Request, status
18
+ from pydantic import BaseModel, Field
19
+
20
+ from ciris_engine.logic.config.db_paths import get_audit_db_full_path
21
+ from ciris_engine.logic.setup.first_run import get_default_config_path, is_first_run
22
+ from ciris_engine.logic.setup.wizard import create_env_file, generate_encryption_key
23
+ from ciris_engine.schemas.api.responses import SuccessResponse
24
+
25
+ from ..dependencies.auth import AuthContext, get_auth_context
26
+
27
+ router = APIRouter(prefix="/setup", tags=["setup"])
28
+ logger = logging.getLogger(__name__)
29
+
30
+ # Constants
31
+ FIELD_DESC_DISPLAY_NAME = "Display name"
32
+
33
+ # ============================================================================
34
+ # Request/Response Schemas
35
+ # ============================================================================
36
+
37
+
38
+ class LLMProvider(BaseModel):
39
+ """LLM provider configuration."""
40
+
41
+ id: str = Field(..., description="Provider ID (openai, local, other)")
42
+ name: str = Field(..., description=FIELD_DESC_DISPLAY_NAME)
43
+ description: str = Field(..., description="Provider description")
44
+ requires_api_key: bool = Field(..., description="Whether API key is required")
45
+ requires_base_url: bool = Field(..., description="Whether base URL is required")
46
+ requires_model: bool = Field(..., description="Whether model name is required")
47
+ default_base_url: Optional[str] = Field(None, description="Default base URL if applicable")
48
+ default_model: Optional[str] = Field(None, description="Default model name if applicable")
49
+ examples: List[str] = Field(default_factory=list, description="Example configurations")
50
+
51
+
52
+ class AgentTemplate(BaseModel):
53
+ """Agent identity template."""
54
+
55
+ id: str = Field(..., description="Template ID")
56
+ name: str = Field(..., description=FIELD_DESC_DISPLAY_NAME)
57
+ description: str = Field(..., description="Template description")
58
+ identity: str = Field(..., description="Agent identity/purpose")
59
+ example_use_cases: List[str] = Field(default_factory=list, description="Example use cases")
60
+ supported_sops: List[str] = Field(
61
+ default_factory=list, description="Supported Standard Operating Procedures (SOPs) for ticket workflows"
62
+ )
63
+
64
+ # Book VI Stewardship (REQUIRED for all templates)
65
+ stewardship_tier: int = Field(
66
+ ..., ge=1, le=5, description="Book VI Stewardship Tier (1-5, higher = more oversight)"
67
+ )
68
+ creator_id: str = Field(..., description="Creator/team identifier who signed this template")
69
+ signature: str = Field(..., description="Cryptographic signature verifying template authenticity")
70
+
71
+
72
+ class AdapterConfig(BaseModel):
73
+ """Adapter configuration."""
74
+
75
+ id: str = Field(..., description="Adapter ID (api, cli, discord, reddit)")
76
+ name: str = Field(..., description=FIELD_DESC_DISPLAY_NAME)
77
+ description: str = Field(..., description="Adapter description")
78
+ enabled_by_default: bool = Field(False, description="Whether enabled by default")
79
+ required_env_vars: List[str] = Field(default_factory=list, description="Required environment variables")
80
+ optional_env_vars: List[str] = Field(default_factory=list, description="Optional environment variables")
81
+ platform_requirements: List[str] = Field(
82
+ default_factory=list, description="Platform requirements (e.g., 'android_play_integrity')"
83
+ )
84
+ platform_available: bool = Field(True, description="Whether available on current platform")
85
+
86
+
87
+ class SetupStatusResponse(BaseModel):
88
+ """Setup status information."""
89
+
90
+ is_first_run: bool = Field(..., description="Whether this is first run")
91
+ config_exists: bool = Field(..., description="Whether config file exists")
92
+ config_path: Optional[str] = Field(None, description="Path to config file if exists")
93
+ setup_required: bool = Field(..., description="Whether setup is required")
94
+
95
+
96
+ class LLMValidationRequest(BaseModel):
97
+ """Request to validate LLM configuration."""
98
+
99
+ provider: str = Field(..., description="Provider ID (openai, local, other)")
100
+ api_key: str = Field(..., description="API key")
101
+ base_url: Optional[str] = Field(None, description="Base URL for OpenAI-compatible endpoints")
102
+ model: Optional[str] = Field(None, description="Model name")
103
+
104
+
105
+ class LLMValidationResponse(BaseModel):
106
+ """Response from LLM validation."""
107
+
108
+ valid: bool = Field(..., description="Whether configuration is valid")
109
+ message: str = Field(..., description="Validation message")
110
+ error: Optional[str] = Field(None, description="Error details if validation failed")
111
+
112
+
113
+ class SetupCompleteRequest(BaseModel):
114
+ """Request to complete setup."""
115
+
116
+ # Primary LLM Configuration
117
+ llm_provider: str = Field(..., description="LLM provider ID")
118
+ llm_api_key: str = Field(..., description="LLM API key")
119
+ llm_base_url: Optional[str] = Field(None, description="LLM base URL")
120
+ llm_model: Optional[str] = Field(None, description="LLM model name")
121
+
122
+ # Backup/Secondary LLM Configuration (Optional)
123
+ backup_llm_api_key: Optional[str] = Field(None, description="Backup LLM API key (CIRIS_OPENAI_API_KEY_2)")
124
+ backup_llm_base_url: Optional[str] = Field(None, description="Backup LLM base URL (CIRIS_OPENAI_API_BASE_2)")
125
+ backup_llm_model: Optional[str] = Field(None, description="Backup LLM model name (CIRIS_OPENAI_MODEL_NAME_2)")
126
+
127
+ # Template Selection
128
+ template_id: str = Field(default="general", description="Agent template ID")
129
+
130
+ # Adapter Configuration
131
+ enabled_adapters: List[str] = Field(default=["api"], description="List of enabled adapters")
132
+ adapter_config: Dict[str, Any] = Field(default_factory=dict, description="Adapter-specific configuration")
133
+
134
+ # User Configuration - Dual Password Support
135
+ admin_username: str = Field(default="admin", description="New user's username")
136
+ admin_password: Optional[str] = Field(
137
+ None,
138
+ description="New user's password (min 8 characters). Optional for OAuth users - if not provided, a random password is generated and password auth is disabled for this user.",
139
+ )
140
+ system_admin_password: Optional[str] = Field(
141
+ None, description="System admin password to replace default (min 8 characters, optional)"
142
+ )
143
+ # OAuth indicator - frontend sets this when user authenticated via OAuth (Google, etc.)
144
+ oauth_provider: Optional[str] = Field(
145
+ None, description="OAuth provider used for authentication (e.g., 'google'). If set, local password is optional."
146
+ )
147
+ oauth_external_id: Optional[str] = Field(
148
+ None, description="OAuth external ID (e.g., Google user ID). Required if oauth_provider is set."
149
+ )
150
+ oauth_email: Optional[str] = Field(None, description="OAuth email address from the provider.")
151
+
152
+ # Application Configuration
153
+ agent_port: int = Field(default=8080, description="Agent API port")
154
+
155
+
156
+ class SetupConfigResponse(BaseModel):
157
+ """Current setup configuration."""
158
+
159
+ # Primary LLM Configuration
160
+ llm_provider: Optional[str] = Field(None, description="Current LLM provider")
161
+ llm_base_url: Optional[str] = Field(None, description="Current LLM base URL")
162
+ llm_model: Optional[str] = Field(None, description="Current LLM model")
163
+ llm_api_key_set: bool = Field(False, description="Whether API key is configured")
164
+
165
+ # Backup/Secondary LLM Configuration
166
+ backup_llm_base_url: Optional[str] = Field(None, description="Backup LLM base URL")
167
+ backup_llm_model: Optional[str] = Field(None, description="Backup LLM model")
168
+ backup_llm_api_key_set: bool = Field(False, description="Whether backup API key is configured")
169
+
170
+ # Template
171
+ template_id: Optional[str] = Field(None, description="Current template ID")
172
+
173
+ # Adapters
174
+ enabled_adapters: List[str] = Field(default_factory=list, description="Currently enabled adapters")
175
+
176
+ # Application
177
+ agent_port: int = Field(default=8080, description="Current agent port")
178
+
179
+
180
+ class CreateUserRequest(BaseModel):
181
+ """Request to create initial admin user."""
182
+
183
+ username: str = Field(..., description="Admin username")
184
+ password: str = Field(..., description="Admin password (min 8 characters)")
185
+
186
+
187
+ class ChangePasswordRequest(BaseModel):
188
+ """Request to change admin password."""
189
+
190
+ old_password: str = Field(..., description="Current password")
191
+ new_password: str = Field(..., description="New password (min 8 characters)")
192
+
193
+
194
+ # ============================================================================
195
+ # Helper Functions
196
+ # ============================================================================
197
+
198
+
199
+ def _is_setup_allowed_without_auth() -> bool:
200
+ """Check if setup endpoints should be accessible without authentication.
201
+
202
+ Returns True during first-run (no config exists).
203
+ Returns False after setup (config exists, requires auth).
204
+ """
205
+ return is_first_run()
206
+
207
+
208
+ def _get_llm_providers() -> List[LLMProvider]:
209
+ """Get list of supported LLM providers."""
210
+ return [
211
+ LLMProvider(
212
+ id="openai",
213
+ name="OpenAI",
214
+ description="Official OpenAI API (GPT-4, GPT-5.2, etc.)",
215
+ requires_api_key=True,
216
+ requires_base_url=False,
217
+ requires_model=True,
218
+ default_base_url=None,
219
+ default_model="gpt-5.2",
220
+ examples=[
221
+ "Standard OpenAI API",
222
+ "Azure OpenAI Service",
223
+ ],
224
+ ),
225
+ LLMProvider(
226
+ id="anthropic",
227
+ name="Anthropic",
228
+ description="Claude models (Claude 3.5 Sonnet, Opus, Haiku)",
229
+ requires_api_key=True,
230
+ requires_base_url=False,
231
+ requires_model=True,
232
+ default_base_url=None,
233
+ default_model="claude-3-5-sonnet-20241022",
234
+ examples=[
235
+ "Claude 3.5 Sonnet",
236
+ "Claude 3 Opus",
237
+ ],
238
+ ),
239
+ LLMProvider(
240
+ id="openrouter",
241
+ name="OpenRouter",
242
+ description="Access 100+ models via OpenRouter",
243
+ requires_api_key=True,
244
+ requires_base_url=False,
245
+ requires_model=True,
246
+ default_base_url="https://openrouter.ai/api/v1",
247
+ default_model="meta-llama/llama-4-maverick",
248
+ examples=[
249
+ "Llama 4 Maverick",
250
+ "GPT-4o via OpenRouter",
251
+ ],
252
+ ),
253
+ LLMProvider(
254
+ id="groq",
255
+ name="Groq",
256
+ description="Ultra-fast LPU inference (Llama 3.3, Mixtral)",
257
+ requires_api_key=True,
258
+ requires_base_url=False,
259
+ requires_model=True,
260
+ default_base_url="https://api.groq.com/openai/v1",
261
+ default_model="llama-3.3-70b-versatile",
262
+ examples=[
263
+ "Llama 3.3 70B Versatile",
264
+ "Llama 3.2 90B Vision",
265
+ ],
266
+ ),
267
+ LLMProvider(
268
+ id="together",
269
+ name="Together AI",
270
+ description="High-performance open models",
271
+ requires_api_key=True,
272
+ requires_base_url=False,
273
+ requires_model=True,
274
+ default_base_url="https://api.together.xyz/v1",
275
+ default_model="meta-llama/Llama-3.3-70B-Instruct-Turbo",
276
+ examples=[
277
+ "Llama 3.3 70B Turbo",
278
+ "Llama Vision Free",
279
+ ],
280
+ ),
281
+ LLMProvider(
282
+ id="google",
283
+ name="Google AI",
284
+ description="Gemini models (Gemini 2.0, 1.5 Pro)",
285
+ requires_api_key=True,
286
+ requires_base_url=False,
287
+ requires_model=True,
288
+ default_base_url="https://generativelanguage.googleapis.com/v1beta",
289
+ default_model="gemini-2.0-flash-exp",
290
+ examples=[
291
+ "Gemini 2.0 Flash",
292
+ "Gemini 1.5 Pro",
293
+ ],
294
+ ),
295
+ LLMProvider(
296
+ id="local",
297
+ name="Local LLM",
298
+ description="Local LLM server (Ollama, LM Studio, vLLM, etc.)",
299
+ requires_api_key=False,
300
+ requires_base_url=True,
301
+ requires_model=True,
302
+ default_base_url="http://localhost:11434",
303
+ default_model="llama3",
304
+ examples=[
305
+ "Ollama: http://localhost:11434",
306
+ "LM Studio: http://localhost:1234/v1",
307
+ "vLLM: http://localhost:8000/v1",
308
+ "LocalAI: http://localhost:8080/v1",
309
+ ],
310
+ ),
311
+ LLMProvider(
312
+ id="other",
313
+ name="Other",
314
+ description="Any OpenAI-compatible API endpoint",
315
+ requires_api_key=True,
316
+ requires_base_url=True,
317
+ requires_model=True,
318
+ default_base_url=None,
319
+ default_model=None,
320
+ examples=[
321
+ "Custom endpoints",
322
+ "Private deployments",
323
+ ],
324
+ ),
325
+ ]
326
+
327
+
328
+ def _get_agent_templates() -> List[AgentTemplate]:
329
+ """Get list of available agent templates from ciris_templates directory.
330
+
331
+ Returns template metadata for GUI display including:
332
+ - 4 default DSAR SOPs for GDPR compliance
333
+ - Book VI Stewardship information with creator signature
334
+ """
335
+ import yaml
336
+
337
+ from ciris_engine.logic.utils.path_resolution import get_template_directory
338
+ from ciris_engine.schemas.config.agent import AgentTemplate as ConfigAgentTemplate
339
+
340
+ templates: List[AgentTemplate] = []
341
+ template_dir = get_template_directory()
342
+
343
+ logger.info(f"[SETUP TEMPLATES] Loading templates from: {template_dir}")
344
+ logger.info(f"[SETUP TEMPLATES] Directory exists: {template_dir.exists()}")
345
+
346
+ # Skip test.yaml and backup files
347
+ skip_templates = {"test.yaml", "CIRIS_TEMPLATE_GUIDE.md"}
348
+
349
+ yaml_files = list(template_dir.glob("*.yaml"))
350
+ logger.info(f"[SETUP TEMPLATES] Found {len(yaml_files)} .yaml files: {[f.name for f in yaml_files]}")
351
+
352
+ for template_file in yaml_files:
353
+ if template_file.name in skip_templates or template_file.name.endswith(".backup"):
354
+ logger.info(f"[SETUP TEMPLATES] Skipping: {template_file.name}")
355
+ continue
356
+
357
+ try:
358
+ logger.info(f"[SETUP TEMPLATES] Loading: {template_file.name}")
359
+ with open(template_file, "r") as f:
360
+ template_data = yaml.safe_load(f)
361
+
362
+ # Load and validate template
363
+ config_template = ConfigAgentTemplate(**template_data)
364
+
365
+ # Extract SOP names from tickets config
366
+ supported_sops: List[str] = []
367
+ if config_template.tickets and config_template.tickets.sops:
368
+ supported_sops = [sop.sop for sop in config_template.tickets.sops]
369
+
370
+ # Extract stewardship info
371
+ stewardship_tier = 3 # Default medium risk
372
+ creator_id = "Unknown"
373
+ signature = "unsigned"
374
+
375
+ if config_template.stewardship:
376
+ stewardship_tier = config_template.stewardship.stewardship_tier
377
+ creator_id = config_template.stewardship.creator_ledger_entry.creator_id
378
+ signature = config_template.stewardship.creator_ledger_entry.signature
379
+
380
+ # Create API response template
381
+ template = AgentTemplate(
382
+ id=template_file.stem, # Use filename without .yaml as ID
383
+ name=config_template.name,
384
+ description=config_template.description,
385
+ identity=config_template.role_description,
386
+ example_use_cases=[], # Can be added to template schema later
387
+ supported_sops=supported_sops,
388
+ stewardship_tier=stewardship_tier,
389
+ creator_id=creator_id,
390
+ signature=signature,
391
+ )
392
+
393
+ templates.append(template)
394
+ logger.info(f"[SETUP TEMPLATES] Loaded: id={template.id}, name={template.name}")
395
+
396
+ except Exception as e:
397
+ logger.warning(f"[SETUP TEMPLATES] Failed to load template {template_file}: {e}")
398
+ continue
399
+
400
+ logger.info(f"[SETUP TEMPLATES] Total templates loaded: {len(templates)}")
401
+ logger.info(f"[SETUP TEMPLATES] Template IDs: {[t.id for t in templates]}")
402
+ return templates
403
+
404
+
405
+ def _get_available_adapters() -> List[AdapterConfig]:
406
+ """Get list of available adapters."""
407
+ return [
408
+ AdapterConfig(
409
+ id="api",
410
+ name="Web API",
411
+ description="RESTful API server with built-in web interface",
412
+ enabled_by_default=True,
413
+ required_env_vars=[],
414
+ optional_env_vars=["CIRIS_API_PORT", "NEXT_PUBLIC_API_BASE_URL"],
415
+ ),
416
+ AdapterConfig(
417
+ id="cli",
418
+ name="Command Line",
419
+ description="Interactive command-line interface",
420
+ enabled_by_default=False,
421
+ required_env_vars=[],
422
+ optional_env_vars=[],
423
+ ),
424
+ AdapterConfig(
425
+ id="discord",
426
+ name="Discord Bot",
427
+ description="Discord bot integration for server moderation and interaction",
428
+ enabled_by_default=False,
429
+ required_env_vars=["DISCORD_BOT_TOKEN"],
430
+ optional_env_vars=["DISCORD_CHANNEL_ID", "DISCORD_GUILD_ID"],
431
+ ),
432
+ AdapterConfig(
433
+ id="reddit",
434
+ name="Reddit Integration",
435
+ description="Reddit bot for r/ciris monitoring and interaction",
436
+ enabled_by_default=False,
437
+ required_env_vars=[
438
+ "CIRIS_REDDIT_CLIENT_ID",
439
+ "CIRIS_REDDIT_CLIENT_SECRET",
440
+ "CIRIS_REDDIT_USERNAME",
441
+ "CIRIS_REDDIT_PASSWORD",
442
+ ],
443
+ optional_env_vars=["CIRIS_REDDIT_SUBREDDIT"],
444
+ ),
445
+ ]
446
+
447
+
448
+ def _validate_api_key_for_provider(config: LLMValidationRequest) -> Optional[LLMValidationResponse]:
449
+ """Validate API key based on provider type.
450
+
451
+ Returns:
452
+ LLMValidationResponse if validation fails, None if valid
453
+ """
454
+ if config.provider == "openai":
455
+ if not config.api_key or config.api_key == "your_openai_api_key_here":
456
+ return LLMValidationResponse(
457
+ valid=False,
458
+ message="Invalid API key",
459
+ error="OpenAI requires a valid API key starting with 'sk-'",
460
+ )
461
+ elif config.provider != "local" and not config.api_key:
462
+ # Other non-local providers need API key
463
+ return LLMValidationResponse(valid=False, message="API key required", error="This provider requires an API key")
464
+ return None
465
+
466
+
467
+ def _classify_llm_connection_error(error: Exception, base_url: Optional[str]) -> LLMValidationResponse:
468
+ """Classify and format LLM connection errors.
469
+
470
+ Args:
471
+ error: The exception that occurred
472
+ base_url: The base URL being connected to
473
+
474
+ Returns:
475
+ Formatted error response
476
+ """
477
+ error_str = str(error)
478
+
479
+ if "401" in error_str or "Unauthorized" in error_str:
480
+ return LLMValidationResponse(
481
+ valid=False,
482
+ message="Authentication failed",
483
+ error="Invalid API key. Please check your credentials.",
484
+ )
485
+ if "404" in error_str or "Not Found" in error_str:
486
+ return LLMValidationResponse(
487
+ valid=False,
488
+ message="Endpoint not found",
489
+ error=f"Could not reach {base_url}. Please check the URL.",
490
+ )
491
+ if "timeout" in error_str.lower():
492
+ return LLMValidationResponse(
493
+ valid=False,
494
+ message="Connection timeout",
495
+ error="Could not connect to LLM server. Please check if it's running.",
496
+ )
497
+ return LLMValidationResponse(valid=False, message="Connection failed", error=f"Error: {error_str}")
498
+
499
+
500
+ async def _validate_llm_connection(config: LLMValidationRequest) -> LLMValidationResponse:
501
+ """Validate LLM configuration by attempting a connection.
502
+
503
+ Args:
504
+ config: LLM configuration to validate
505
+
506
+ Returns:
507
+ Validation response with success/failure status
508
+ """
509
+ logger.info("[VALIDATE_LLM] " + "=" * 50)
510
+ logger.info(f"[VALIDATE_LLM] Starting validation for provider: {config.provider}")
511
+ logger.info(
512
+ f"[VALIDATE_LLM] API key provided: {bool(config.api_key)} (length: {len(config.api_key) if config.api_key else 0})"
513
+ )
514
+ logger.info(
515
+ f"[VALIDATE_LLM] API key prefix: {config.api_key[:20] + '...' if config.api_key and len(config.api_key) > 20 else config.api_key}"
516
+ )
517
+ logger.info(f"[VALIDATE_LLM] Base URL: {config.base_url}")
518
+ logger.info(f"[VALIDATE_LLM] Model: {config.model}")
519
+
520
+ try:
521
+ # Validate API key for provider type
522
+ api_key_error = _validate_api_key_for_provider(config)
523
+ if api_key_error:
524
+ logger.warning(f"[VALIDATE_LLM] API key validation FAILED: {api_key_error.error}")
525
+ return api_key_error
526
+
527
+ logger.info("[VALIDATE_LLM] API key format validation passed")
528
+
529
+ # Import OpenAI client
530
+ from openai import AsyncOpenAI
531
+
532
+ # Build client configuration
533
+ client_kwargs: Dict[str, Any] = {"api_key": config.api_key or "local"} # Local LLMs can use placeholder
534
+ if config.base_url:
535
+ client_kwargs["base_url"] = config.base_url
536
+
537
+ logger.info(f"[VALIDATE_LLM] Creating OpenAI client with base_url: {client_kwargs.get('base_url', 'default')}")
538
+
539
+ # Create client and test connection
540
+ client = AsyncOpenAI(**client_kwargs)
541
+
542
+ try:
543
+ logger.info("[VALIDATE_LLM] Attempting to list models from API...")
544
+ models = await client.models.list()
545
+ model_count = len(models.data) if hasattr(models, "data") else 0
546
+
547
+ logger.info(f"[VALIDATE_LLM] SUCCESS! Found {model_count} models")
548
+ return LLMValidationResponse(
549
+ valid=True,
550
+ message=f"Connection successful! Found {model_count} available models.",
551
+ error=None,
552
+ )
553
+ except Exception as e:
554
+ logger.error(f"[VALIDATE_LLM] API call FAILED: {type(e).__name__}: {e}")
555
+ result = _classify_llm_connection_error(e, config.base_url)
556
+ logger.error(f"[VALIDATE_LLM] Classified error - valid: {result.valid}, error: {result.error}")
557
+ return result
558
+
559
+ except Exception as e:
560
+ logger.error(f"[VALIDATE_LLM] Unexpected error: {type(e).__name__}: {e}")
561
+ return LLMValidationResponse(valid=False, message="Validation error", error=str(e))
562
+
563
+
564
+ # =============================================================================
565
+ # SETUP USER HELPER FUNCTIONS (extracted for cognitive complexity reduction)
566
+ # =============================================================================
567
+
568
+
569
+ async def _link_oauth_identity_to_wa(auth_service: Any, setup: "SetupCompleteRequest", wa_cert: Any) -> Any:
570
+ """Link OAuth identity to WA, handling existing links gracefully.
571
+
572
+ Returns the WA cert to use (may be updated if existing link found).
573
+ """
574
+ from ciris_engine.schemas.services.authority_core import WARole
575
+
576
+ logger.debug("CIRIS_SETUP_DEBUG *** ENTERING OAuth linking block ***")
577
+ logger.debug( # NOSONAR - provider:external_id is not a secret, it's a provider-assigned ID
578
+ f"CIRIS_SETUP_DEBUG Linking OAuth identity: {setup.oauth_provider}:{setup.oauth_external_id} to WA {wa_cert.wa_id}"
579
+ )
580
+
581
+ try:
582
+ # First check if OAuth identity is already linked to another WA
583
+ existing_wa = await auth_service.get_wa_by_oauth(setup.oauth_provider, setup.oauth_external_id)
584
+ if existing_wa and existing_wa.wa_id != wa_cert.wa_id:
585
+ logger.info(f"CIRIS_SETUP_DEBUG OAuth identity already linked to WA {existing_wa.wa_id}")
586
+ logger.info(
587
+ "CIRIS_SETUP_DEBUG During first-run setup, we'll update the existing WA to be ROOT instead of creating new"
588
+ )
589
+ # Update the existing WA to have ROOT role and update its name
590
+ await auth_service.update_wa(
591
+ wa_id=existing_wa.wa_id,
592
+ name=setup.admin_username,
593
+ role=WARole.ROOT,
594
+ )
595
+ logger.info(f"CIRIS_SETUP_DEBUG ✅ Updated existing WA {existing_wa.wa_id} to ROOT role")
596
+ return existing_wa
597
+
598
+ # No existing link or same WA - safe to link
599
+ await auth_service.link_oauth_identity(
600
+ wa_id=wa_cert.wa_id,
601
+ provider=setup.oauth_provider,
602
+ external_id=setup.oauth_external_id,
603
+ account_name=setup.admin_username,
604
+ metadata={"email": setup.oauth_email} if setup.oauth_email else None,
605
+ primary=True,
606
+ )
607
+ logger.debug( # NOSONAR - provider:external_id is not a secret
608
+ f"CIRIS_SETUP_DEBUG ✅ SUCCESS: Linked OAuth {setup.oauth_provider}:{setup.oauth_external_id} to WA {wa_cert.wa_id}"
609
+ )
610
+ except Exception as e:
611
+ logger.error(f"CIRIS_SETUP_DEBUG ❌ FAILED to link OAuth identity: {e}", exc_info=True)
612
+ # Don't fail setup if OAuth linking fails - user can still use password
613
+
614
+ return wa_cert
615
+
616
+
617
+ def _log_oauth_linking_skip(setup: "SetupCompleteRequest") -> None:
618
+ """Log debug information when OAuth linking is skipped."""
619
+ logger.info("CIRIS_SETUP_DEBUG *** SKIPPING OAuth linking block - condition not met ***")
620
+ if not setup.oauth_provider:
621
+ logger.info("CIRIS_SETUP_DEBUG Reason: oauth_provider is falsy/empty")
622
+ if not setup.oauth_external_id:
623
+ logger.info("CIRIS_SETUP_DEBUG Reason: oauth_external_id is falsy/empty")
624
+
625
+
626
+ async def _update_system_admin_password(auth_service: Any, setup: "SetupCompleteRequest", exclude_wa_id: str) -> None:
627
+ """Update the default admin password if specified."""
628
+ if not setup.system_admin_password:
629
+ return
630
+
631
+ logger.info("Updating default admin password...")
632
+ all_was = await auth_service.list_was(active_only=True)
633
+ admin_wa = next((wa for wa in all_was if wa.name == "admin" and wa.wa_id != exclude_wa_id), None)
634
+
635
+ if admin_wa:
636
+ admin_password_hash = auth_service.hash_password(setup.system_admin_password)
637
+ await auth_service.update_wa(wa_id=admin_wa.wa_id, password_hash=admin_password_hash)
638
+ logger.info("✅ Updated admin password")
639
+ else:
640
+ logger.warning("⚠️ Default admin WA not found")
641
+
642
+
643
+ async def _check_existing_oauth_wa(auth_service: Any, setup: "SetupCompleteRequest") -> tuple[Optional[Any], bool]:
644
+ """Check if OAuth user already exists and update to ROOT if found.
645
+
646
+ Returns:
647
+ Tuple of (wa_cert, was_found) where wa_cert is the WA certificate and
648
+ was_found indicates if an existing WA was found and updated.
649
+ """
650
+ from ciris_engine.schemas.services.authority_core import WARole
651
+
652
+ if not (setup.oauth_provider and setup.oauth_external_id):
653
+ return None, False
654
+
655
+ logger.debug( # NOSONAR - provider:external_id is not a secret
656
+ f"CIRIS_USER_CREATE: Checking for existing OAuth user: {setup.oauth_provider}:{setup.oauth_external_id}"
657
+ )
658
+ existing_wa = await auth_service.get_wa_by_oauth(setup.oauth_provider, setup.oauth_external_id)
659
+
660
+ if not existing_wa:
661
+ logger.info("CIRIS_USER_CREATE: No existing WA found for OAuth user - will create new")
662
+ return None, False
663
+
664
+ logger.info(f"CIRIS_USER_CREATE: ✓ Found existing WA for OAuth user: {existing_wa.wa_id}")
665
+ logger.info(f"CIRIS_USER_CREATE: Current role: {existing_wa.role}")
666
+ logger.info(f"CIRIS_USER_CREATE: Current name: {existing_wa.name}")
667
+
668
+ # Update existing WA to ROOT role instead of creating new one
669
+ logger.info(
670
+ f"CIRIS_USER_CREATE: Updating existing WA {existing_wa.wa_id} to ROOT role (keeping name: {existing_wa.name})"
671
+ )
672
+ await auth_service.update_wa(wa_id=existing_wa.wa_id, role=WARole.ROOT)
673
+ logger.info(f"CIRIS_USER_CREATE: ✅ Updated existing OAuth WA to ROOT: {existing_wa.wa_id}")
674
+
675
+ return existing_wa, True
676
+
677
+
678
+ async def _create_new_wa(auth_service: Any, setup: "SetupCompleteRequest") -> Any:
679
+ """Create a new WA certificate for the setup user.
680
+
681
+ Returns:
682
+ WA certificate for the newly created user
683
+ """
684
+ from ciris_engine.schemas.services.authority_core import WARole
685
+
686
+ logger.info(f"CIRIS_USER_CREATE: Creating NEW user: {setup.admin_username} with role: {WARole.ROOT}")
687
+
688
+ # Use OAuth email if available, otherwise generate local email
689
+ user_email = setup.oauth_email or f"{setup.admin_username}@local"
690
+ masked_email = (user_email[:3] + "***@" + user_email.split("@")[-1]) if "@" in user_email else user_email
691
+ logger.debug(f"CIRIS_USER_CREATE: User email: {masked_email}") # NOSONAR - email masked
692
+
693
+ # List existing WAs before creation for debugging
694
+ existing_was = await auth_service.list_was(active_only=False)
695
+ logger.info(f"CIRIS_USER_CREATE: Existing WAs before creation: {len(existing_was)}")
696
+ for wa in existing_was:
697
+ logger.info(f"CIRIS_USER_CREATE: - {wa.wa_id}: name={wa.name}, role={wa.role}")
698
+
699
+ # Create WA certificate
700
+ wa_cert = await auth_service.create_wa(
701
+ name=setup.admin_username,
702
+ email=user_email,
703
+ scopes=["read:any", "write:any"], # ROOT gets full scopes
704
+ role=WARole.ROOT,
705
+ )
706
+ logger.info(f"CIRIS_USER_CREATE: ✅ Created NEW WA: {wa_cert.wa_id}")
707
+
708
+ return wa_cert
709
+
710
+
711
+ async def _set_password_for_wa(auth_service: Any, setup: "SetupCompleteRequest", wa_cert: Any) -> None:
712
+ """Set password hash for non-OAuth users."""
713
+ is_oauth_setup = bool(setup.oauth_provider and setup.oauth_external_id)
714
+
715
+ if is_oauth_setup:
716
+ logger.info(f"CIRIS_USER_CREATE: Skipping password hash for OAuth user: {wa_cert.wa_id}")
717
+ return
718
+
719
+ # Hash password and update WA (admin_password is guaranteed set by validation above)
720
+ assert setup.admin_password is not None, "admin_password should be set by validation"
721
+ password_hash = auth_service.hash_password(setup.admin_password)
722
+ await auth_service.update_wa(wa_id=wa_cert.wa_id, password_hash=password_hash)
723
+ logger.info(f"CIRIS_USER_CREATE: Password hash set for WA: {wa_cert.wa_id}")
724
+
725
+
726
+ async def _ensure_system_wa(auth_service: Any) -> None:
727
+ """Ensure system WA exists for signing system tasks."""
728
+ system_wa_id = await auth_service.ensure_system_wa_exists()
729
+ if system_wa_id:
730
+ logger.info(f"✅ System WA ready: {system_wa_id}")
731
+ else:
732
+ logger.warning("⚠️ Could not create system WA - deferral handling may not work")
733
+
734
+
735
+ async def _log_wa_list(auth_service: Any, phase: str) -> None:
736
+ """Log list of WAs for debugging purposes."""
737
+ was = await auth_service.list_was(active_only=False)
738
+ logger.info(f"CIRIS_USER_CREATE: WAs {phase}: {len(was)}")
739
+ for wa in was:
740
+ logger.info(f"CIRIS_USER_CREATE: - {wa.wa_id}: name={wa.name}, role={wa.role}")
741
+
742
+
743
+ async def _create_setup_users(setup: SetupCompleteRequest, auth_db_path: str) -> None:
744
+ """Create users immediately during setup completion.
745
+
746
+ This is called during setup completion to create users without waiting for restart.
747
+ Creates users directly in the database using authentication store functions.
748
+
749
+ IMPORTANT: For OAuth users, we check if they already exist and update to ROOT instead
750
+ of creating a duplicate WA. This prevents multiple ROOT users from being created.
751
+
752
+ Args:
753
+ setup: Setup configuration with user details
754
+ auth_db_path: Path to the audit database (from running application)
755
+ """
756
+ from ciris_engine.logic.services.infrastructure.authentication.service import AuthenticationService
757
+ from ciris_engine.logic.services.lifecycle.time.service import TimeService
758
+
759
+ logger.info("=" * 70)
760
+ logger.info("CIRIS_USER_CREATE: _create_setup_users() called")
761
+ logger.info("=" * 70)
762
+ logger.info(f"CIRIS_USER_CREATE: auth_db_path = {auth_db_path}")
763
+ logger.info(f"CIRIS_USER_CREATE: admin_username = {setup.admin_username}")
764
+ logger.info(f"CIRIS_USER_CREATE: oauth_provider = {repr(setup.oauth_provider)}")
765
+ logger.info(f"CIRIS_USER_CREATE: oauth_external_id = {repr(setup.oauth_external_id)}")
766
+ logger.info(f"CIRIS_USER_CREATE: oauth_email = {repr(setup.oauth_email)}")
767
+
768
+ # Create temporary authentication service for user creation
769
+ time_service = TimeService()
770
+ await time_service.start()
771
+
772
+ auth_service = AuthenticationService(
773
+ db_path=auth_db_path, time_service=time_service, key_dir=None # Use default ~/.ciris/
774
+ )
775
+ await auth_service.start()
776
+
777
+ try:
778
+ # Check if OAuth user already exists and update to ROOT if found
779
+ wa_cert, _ = await _check_existing_oauth_wa(auth_service, setup)
780
+
781
+ # Create new WA if we didn't find an existing OAuth user
782
+ if wa_cert is None:
783
+ wa_cert = await _create_new_wa(auth_service, setup)
784
+
785
+ # Set password for non-OAuth users
786
+ await _set_password_for_wa(auth_service, setup, wa_cert)
787
+
788
+ # Log WAs after creation for debugging
789
+ await _log_wa_list(auth_service, "after setup")
790
+
791
+ # Ensure system WA exists
792
+ await _ensure_system_wa(auth_service)
793
+
794
+ # CIRIS_SETUP_DEBUG: Log OAuth linking decision
795
+ logger.debug("CIRIS_SETUP_DEBUG _create_setup_users() OAuth linking check:")
796
+ logger.debug(f"CIRIS_SETUP_DEBUG setup.oauth_provider = {repr(setup.oauth_provider)}")
797
+ logger.debug(f"CIRIS_SETUP_DEBUG setup.oauth_external_id = {repr(setup.oauth_external_id)}")
798
+ logger.debug(f"CIRIS_SETUP_DEBUG bool(setup.oauth_provider) = {bool(setup.oauth_provider)}")
799
+ logger.debug(f"CIRIS_SETUP_DEBUG bool(setup.oauth_external_id) = {bool(setup.oauth_external_id)}")
800
+ oauth_link_condition = bool(setup.oauth_provider) and bool(setup.oauth_external_id)
801
+ logger.debug(f"CIRIS_SETUP_DEBUG Condition (provider AND external_id) = {oauth_link_condition}")
802
+
803
+ # Link OAuth identity if provided - THIS IS CRITICAL for OAuth login to work
804
+ if setup.oauth_provider and setup.oauth_external_id:
805
+ wa_cert = await _link_oauth_identity_to_wa(auth_service, setup, wa_cert)
806
+ else:
807
+ _log_oauth_linking_skip(setup)
808
+
809
+ # Update default admin password if specified
810
+ assert wa_cert is not None, "wa_cert should be set by create_wa or existing WA lookup"
811
+ await _update_system_admin_password(auth_service, setup, wa_cert.wa_id)
812
+
813
+ finally:
814
+ await auth_service.stop()
815
+ await time_service.stop()
816
+
817
+
818
+ def _save_pending_users(setup: SetupCompleteRequest, config_dir: Path) -> None:
819
+ """Save pending user creation info for initialization service.
820
+
821
+ Args:
822
+ setup: Setup configuration with user info
823
+ config_dir: Directory where .env file is saved
824
+ """
825
+ pending_users_file = config_dir / ".ciris_pending_users.json"
826
+
827
+ # Prepare user creation data
828
+ users_data = {
829
+ "created_at": datetime.now(timezone.utc).isoformat(),
830
+ "new_user": {
831
+ "username": setup.admin_username,
832
+ "password": setup.admin_password, # Will be hashed by auth service
833
+ "role": "ADMIN", # New user gets admin role
834
+ },
835
+ }
836
+
837
+ # Add system admin password update if provided
838
+ if setup.system_admin_password:
839
+ users_data["system_admin"] = {
840
+ "username": "admin", # Default system admin username
841
+ "password": setup.system_admin_password, # Will be hashed by auth service
842
+ }
843
+
844
+ # Save to JSON file
845
+ with open(pending_users_file, "w") as f:
846
+ json.dump(users_data, f, indent=2)
847
+
848
+
849
+ def _validate_setup_passwords(setup: SetupCompleteRequest, is_oauth_user: bool) -> str:
850
+ """Validate and potentially generate admin password for setup.
851
+
852
+ For OAuth users without a password, generates a secure random password.
853
+ For non-OAuth users, validates password requirements.
854
+
855
+ Args:
856
+ setup: Setup configuration request
857
+ is_oauth_user: Whether user is authenticating via OAuth
858
+
859
+ Returns:
860
+ Validated or generated admin password
861
+
862
+ Raises:
863
+ HTTPException: If password validation fails
864
+ """
865
+ admin_password = setup.admin_password
866
+
867
+ if not admin_password or len(admin_password) == 0:
868
+ if is_oauth_user:
869
+ # Generate a secure random password for OAuth users
870
+ # They won't use this password - they'll authenticate via OAuth
871
+ admin_password = secrets.token_urlsafe(32)
872
+ logger.info("[Setup Complete] Generated random password for OAuth user (password auth disabled)")
873
+ else:
874
+ # Non-OAuth users MUST provide a password
875
+ raise HTTPException(
876
+ status_code=status.HTTP_400_BAD_REQUEST, detail="New user password must be at least 8 characters"
877
+ )
878
+ elif len(admin_password) < 8:
879
+ # If a password was provided, it must meet minimum requirements
880
+ raise HTTPException(
881
+ status_code=status.HTTP_400_BAD_REQUEST, detail="New user password must be at least 8 characters"
882
+ )
883
+
884
+ # Validate system admin password strength if provided
885
+ if setup.system_admin_password and len(setup.system_admin_password) < 8:
886
+ raise HTTPException(
887
+ status_code=status.HTTP_400_BAD_REQUEST, detail="System admin password must be at least 8 characters"
888
+ )
889
+
890
+ return admin_password
891
+
892
+
893
+ def _save_and_reload_config(setup: SetupCompleteRequest) -> Path:
894
+ """Save setup configuration to .env and reload environment variables.
895
+
896
+ Args:
897
+ setup: Setup configuration request
898
+
899
+ Returns:
900
+ Path to the saved configuration file
901
+ """
902
+ from dotenv import load_dotenv
903
+
904
+ from ciris_engine.logic.utils.path_resolution import get_ciris_home, is_android, is_development_mode
905
+
906
+ logger.info("[Setup Complete] Path resolution:")
907
+ logger.info(f"[Setup Complete] is_android(): {is_android()}")
908
+ logger.info(f"[Setup Complete] is_development_mode(): {is_development_mode()}")
909
+ logger.info(f"[Setup Complete] get_ciris_home(): {get_ciris_home()}")
910
+
911
+ config_path = get_default_config_path()
912
+ config_dir = config_path.parent
913
+ logger.info(f"[Setup Complete] config_path: {config_path}")
914
+ logger.info(f"[Setup Complete] config_dir: {config_dir}")
915
+
916
+ # Ensure directory exists
917
+ config_dir.mkdir(parents=True, exist_ok=True)
918
+ logger.info(f"[Setup Complete] Directory ensured: {config_dir}")
919
+
920
+ # Save configuration
921
+ logger.info(f"[Setup Complete] Saving configuration to: {config_path}")
922
+ _save_setup_config(setup, config_path)
923
+ logger.info("[Setup Complete] Configuration saved successfully!")
924
+
925
+ # Verify the file was written
926
+ if config_path.exists():
927
+ file_size = config_path.stat().st_size
928
+ logger.info(f"[Setup Complete] Verified: .env exists ({file_size} bytes)")
929
+ else:
930
+ logger.error(f"[Setup Complete] ERROR: .env file NOT found at {config_path} after save!")
931
+
932
+ # Reload environment variables from the new .env file
933
+ load_dotenv(config_path, override=True)
934
+ logger.info(f"[Setup Complete] Reloaded environment variables from {config_path}")
935
+
936
+ # Verify key env vars were loaded
937
+ openai_key = os.getenv("OPENAI_API_KEY")
938
+ openai_base = os.getenv("OPENAI_API_BASE")
939
+ logger.info(f"[Setup Complete] After reload - OPENAI_API_KEY: {openai_key[:20] if openai_key else '(not set)'}...")
940
+ logger.info(f"[Setup Complete] After reload - OPENAI_API_BASE: {openai_base}")
941
+
942
+ return config_path
943
+
944
+
945
+ def _save_setup_config(setup: SetupCompleteRequest, config_path: Path) -> None:
946
+ """Save setup configuration to .env file.
947
+
948
+ Args:
949
+ setup: Setup configuration
950
+ config_path: Path to save .env file
951
+ """
952
+ # Determine LLM provider type for env file generation
953
+ llm_provider = setup.llm_provider
954
+ llm_api_key = setup.llm_api_key
955
+ llm_base_url = setup.llm_base_url or ""
956
+ llm_model = setup.llm_model or ""
957
+
958
+ # Create .env file using existing wizard logic
959
+ create_env_file(
960
+ save_path=config_path,
961
+ llm_provider=llm_provider,
962
+ llm_api_key=llm_api_key,
963
+ llm_base_url=llm_base_url,
964
+ llm_model=llm_model,
965
+ agent_port=setup.agent_port,
966
+ )
967
+
968
+ # Append template and adapter configuration
969
+ with open(config_path, "a") as f:
970
+ # Template selection
971
+ f.write("\n# Agent Template\n")
972
+ f.write(f"CIRIS_TEMPLATE={setup.template_id}\n")
973
+
974
+ # Adapter configuration
975
+ f.write("\n# Enabled Adapters\n")
976
+ adapters_str = ",".join(setup.enabled_adapters)
977
+ f.write(f"CIRIS_ADAPTER={adapters_str}\n")
978
+
979
+ # Adapter-specific environment variables
980
+ if setup.adapter_config:
981
+ f.write("\n# Adapter-Specific Configuration\n")
982
+ for key, value in setup.adapter_config.items():
983
+ f.write(f"{key}={value}\n")
984
+
985
+ # Backup/Secondary LLM Configuration (Optional)
986
+ if setup.backup_llm_api_key:
987
+ f.write("\n# Backup/Secondary LLM Configuration\n")
988
+ f.write(f'CIRIS_OPENAI_API_KEY_2="{setup.backup_llm_api_key}"\n')
989
+ if setup.backup_llm_base_url:
990
+ f.write(f'CIRIS_OPENAI_API_BASE_2="{setup.backup_llm_base_url}"\n')
991
+ if setup.backup_llm_model:
992
+ f.write(f'CIRIS_OPENAI_MODEL_NAME_2="{setup.backup_llm_model}"\n')
993
+
994
+
995
+ # ============================================================================
996
+ # Endpoints
997
+ # ============================================================================
998
+
999
+
1000
+ @router.get("/status", response_model=SuccessResponse[SetupStatusResponse])
1001
+ async def get_setup_status() -> SuccessResponse[SetupStatusResponse]:
1002
+ """Check setup status.
1003
+
1004
+ Returns information about whether setup is required.
1005
+ This endpoint is always accessible without authentication.
1006
+ """
1007
+ first_run = is_first_run()
1008
+ config_path = get_default_config_path()
1009
+ config_exists = config_path.exists()
1010
+
1011
+ status = SetupStatusResponse(
1012
+ is_first_run=first_run,
1013
+ config_exists=config_exists,
1014
+ config_path=str(config_path) if config_exists else None,
1015
+ setup_required=first_run,
1016
+ )
1017
+
1018
+ return SuccessResponse(data=status)
1019
+
1020
+
1021
+ @router.get("/providers", response_model=SuccessResponse[List[LLMProvider]])
1022
+ async def list_providers() -> SuccessResponse[List[LLMProvider]]:
1023
+ """List available LLM providers.
1024
+
1025
+ Returns configuration templates for supported LLM providers.
1026
+ This endpoint is always accessible without authentication.
1027
+ """
1028
+ providers = _get_llm_providers()
1029
+ return SuccessResponse(data=providers)
1030
+
1031
+
1032
+ @router.get("/templates", response_model=SuccessResponse[List[AgentTemplate]])
1033
+ async def list_templates() -> SuccessResponse[List[AgentTemplate]]:
1034
+ """List available agent templates.
1035
+
1036
+ Returns pre-configured agent identity templates.
1037
+ This endpoint is always accessible without authentication.
1038
+ """
1039
+ templates = _get_agent_templates()
1040
+ return SuccessResponse(data=templates)
1041
+
1042
+
1043
+ @router.get("/adapters", response_model=SuccessResponse[List[AdapterConfig]])
1044
+ async def list_adapters() -> SuccessResponse[List[AdapterConfig]]:
1045
+ """List available adapters.
1046
+
1047
+ Returns configuration for available communication adapters.
1048
+ This endpoint is always accessible without authentication.
1049
+ """
1050
+ adapters = _get_available_adapters()
1051
+ return SuccessResponse(data=adapters)
1052
+
1053
+
1054
+ @router.get("/models")
1055
+ async def get_model_capabilities_endpoint() -> SuccessResponse[Dict[str, Any]]:
1056
+ """Get CIRIS-compatible LLM model capabilities.
1057
+
1058
+ Returns the on-device model capabilities database for BYOK model selection.
1059
+ Used by the wizard's Advanced settings to show compatible models per provider.
1060
+ This endpoint is always accessible without authentication.
1061
+
1062
+ Returns model info including:
1063
+ - CIRIS compatibility requirements (128K+ context, tool use, vision)
1064
+ - Per-provider model listings with capability flags
1065
+ - Tiers (default, fast, fallback, premium)
1066
+ - Recommendations and rejection reasons
1067
+ """
1068
+ from ciris_engine.config import get_model_capabilities
1069
+
1070
+ try:
1071
+ config = get_model_capabilities()
1072
+
1073
+ # Convert to dict for JSON response
1074
+ return SuccessResponse(
1075
+ data={
1076
+ "version": config.version,
1077
+ "last_updated": config.last_updated.isoformat(),
1078
+ "ciris_requirements": config.ciris_requirements.model_dump(),
1079
+ "providers": {
1080
+ provider_id: {
1081
+ "display_name": provider.display_name,
1082
+ "api_base": provider.api_base,
1083
+ "models": {model_id: model.model_dump() for model_id, model in provider.models.items()},
1084
+ }
1085
+ for provider_id, provider in config.providers.items()
1086
+ },
1087
+ "tiers": {tier_id: tier.model_dump() for tier_id, tier in config.tiers.items()},
1088
+ "rejected_models": {model_id: model.model_dump() for model_id, model in config.rejected_models.items()},
1089
+ }
1090
+ )
1091
+ except Exception as e:
1092
+ logger.error(f"Failed to load model capabilities: {e}")
1093
+ raise HTTPException(
1094
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
1095
+ detail=f"Failed to load model capabilities: {str(e)}",
1096
+ )
1097
+
1098
+
1099
+ @router.get("/models/{provider_id}")
1100
+ async def get_provider_models(provider_id: str) -> SuccessResponse[Dict[str, Any]]:
1101
+ """Get CIRIS-compatible models for a specific provider.
1102
+
1103
+ Returns models for the given provider with compatibility information.
1104
+ Used by the wizard to populate model dropdown after provider selection.
1105
+ """
1106
+ from ciris_engine.config import get_model_capabilities
1107
+
1108
+ try:
1109
+ config = get_model_capabilities()
1110
+
1111
+ if provider_id not in config.providers:
1112
+ raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Provider '{provider_id}' not found")
1113
+
1114
+ provider = config.providers[provider_id]
1115
+ compatible_models = []
1116
+ incompatible_models = []
1117
+
1118
+ for model_id, model in provider.models.items():
1119
+ model_data = {
1120
+ "id": model_id,
1121
+ **model.model_dump(),
1122
+ }
1123
+ if model.ciris_compatible:
1124
+ compatible_models.append(model_data)
1125
+ else:
1126
+ incompatible_models.append(model_data)
1127
+
1128
+ # Sort: recommended first, then by display name
1129
+ compatible_models.sort(key=lambda m: (not m.get("ciris_recommended", False), m["display_name"]))
1130
+
1131
+ return SuccessResponse(
1132
+ data={
1133
+ "provider_id": provider_id,
1134
+ "display_name": provider.display_name,
1135
+ "api_base": provider.api_base,
1136
+ "compatible_models": compatible_models,
1137
+ "incompatible_models": incompatible_models,
1138
+ "ciris_requirements": config.ciris_requirements.model_dump(),
1139
+ }
1140
+ )
1141
+ except HTTPException:
1142
+ raise
1143
+ except Exception as e:
1144
+ logger.error(f"Failed to get provider models: {e}")
1145
+ raise HTTPException(
1146
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
1147
+ detail=f"Failed to get provider models: {str(e)}",
1148
+ )
1149
+
1150
+
1151
+ @router.post("/validate-llm", response_model=SuccessResponse[LLMValidationResponse])
1152
+ async def validate_llm(config: LLMValidationRequest) -> SuccessResponse[LLMValidationResponse]:
1153
+ """Validate LLM configuration.
1154
+
1155
+ Tests the provided LLM configuration by attempting a connection.
1156
+ This endpoint is always accessible without authentication during first-run.
1157
+ """
1158
+ validation_result = await _validate_llm_connection(config)
1159
+ return SuccessResponse(data=validation_result)
1160
+
1161
+
1162
+ @router.post("/complete", response_model=SuccessResponse[Dict[str, str]])
1163
+ async def complete_setup(setup: SetupCompleteRequest, request: Request) -> SuccessResponse[Dict[str, str]]:
1164
+ """Complete initial setup.
1165
+
1166
+ Saves configuration and creates initial admin user.
1167
+ Only accessible during first-run (no authentication required).
1168
+ After setup, authentication is required for reconfiguration.
1169
+ """
1170
+ # CIRIS_SETUP_DEBUG: Comprehensive logging for OAuth identity linking
1171
+ logger.info("CIRIS_SETUP_DEBUG " + "=" * 60)
1172
+ logger.info("CIRIS_SETUP_DEBUG complete_setup() endpoint called")
1173
+ logger.info("CIRIS_SETUP_DEBUG " + "=" * 60)
1174
+
1175
+ # Log ALL OAuth-related fields received from frontend
1176
+ logger.info("CIRIS_SETUP_DEBUG OAuth fields received from frontend:")
1177
+ logger.info(f"CIRIS_SETUP_DEBUG oauth_provider = {repr(setup.oauth_provider)}")
1178
+ logger.info(f"CIRIS_SETUP_DEBUG oauth_external_id = {repr(setup.oauth_external_id)}")
1179
+ logger.info(f"CIRIS_SETUP_DEBUG oauth_email = {repr(setup.oauth_email)}")
1180
+
1181
+ # Check truthiness explicitly
1182
+ logger.debug("CIRIS_SETUP_DEBUG Truthiness checks:")
1183
+ logger.debug(f"CIRIS_SETUP_DEBUG bool(oauth_provider) = {bool(setup.oauth_provider)}")
1184
+ logger.debug(f"CIRIS_SETUP_DEBUG bool(oauth_external_id) = {bool(setup.oauth_external_id)}")
1185
+ logger.debug(f"CIRIS_SETUP_DEBUG oauth_external_id is None = {setup.oauth_external_id is None}")
1186
+ logger.debug(f"CIRIS_SETUP_DEBUG oauth_external_id == '' = {setup.oauth_external_id == ''}")
1187
+
1188
+ # The critical check that determines OAuth linking
1189
+ will_link_oauth = bool(setup.oauth_provider) and bool(setup.oauth_external_id)
1190
+ logger.debug(
1191
+ f"CIRIS_SETUP_DEBUG CRITICAL: Will OAuth linking happen? = {will_link_oauth}"
1192
+ ) # NOSONAR - boolean status only
1193
+ if not will_link_oauth:
1194
+ if not setup.oauth_provider:
1195
+ logger.debug("CIRIS_SETUP_DEBUG Reason: oauth_provider is falsy")
1196
+ if not setup.oauth_external_id:
1197
+ logger.debug("CIRIS_SETUP_DEBUG Reason: oauth_external_id is falsy")
1198
+
1199
+ # Log other setup fields
1200
+ logger.debug("CIRIS_SETUP_DEBUG Other setup fields:")
1201
+ logger.debug(f"CIRIS_SETUP_DEBUG admin_username = {setup.admin_username}")
1202
+ logger.debug(
1203
+ f"CIRIS_SETUP_DEBUG admin_password set = {bool(setup.admin_password)}"
1204
+ ) # NOSONAR - boolean only, not password
1205
+ logger.debug(
1206
+ f"CIRIS_SETUP_DEBUG system_admin_password set = {bool(setup.system_admin_password)}"
1207
+ ) # NOSONAR - boolean only
1208
+ logger.debug(f"CIRIS_SETUP_DEBUG llm_provider = {setup.llm_provider}")
1209
+ logger.debug(f"CIRIS_SETUP_DEBUG template_id = {setup.template_id}")
1210
+
1211
+ # Only allow during first-run
1212
+ if not is_first_run():
1213
+ raise HTTPException(
1214
+ status_code=status.HTTP_403_FORBIDDEN,
1215
+ detail="Setup already completed. Use PUT /v1/setup/config to update configuration.",
1216
+ )
1217
+
1218
+ # Determine if this is an OAuth user (password is optional for OAuth users)
1219
+ is_oauth_user = bool(setup.oauth_provider)
1220
+ logger.debug(
1221
+ f"CIRIS_SETUP_DEBUG is_oauth_user (for password validation) = {is_oauth_user}"
1222
+ ) # NOSONAR - boolean only
1223
+
1224
+ # Validate passwords and potentially generate for OAuth users
1225
+ setup.admin_password = _validate_setup_passwords(setup, is_oauth_user)
1226
+
1227
+ try:
1228
+ # Save configuration and reload environment variables
1229
+ config_path = _save_and_reload_config(setup)
1230
+
1231
+ # Get runtime and database path from the running application
1232
+ runtime = getattr(request.app.state, "runtime", None)
1233
+ if not runtime:
1234
+ raise HTTPException(
1235
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
1236
+ detail="Runtime not available - cannot complete setup",
1237
+ )
1238
+
1239
+ # Get audit database path using same resolution as AuthenticationService
1240
+ # This handles both SQLite and PostgreSQL (adds _auth suffix to database name)
1241
+ auth_db_path = get_audit_db_full_path(runtime.essential_config)
1242
+ logger.info(f"Using runtime audit database: {auth_db_path}")
1243
+
1244
+ # Create users immediately (don't wait for restart)
1245
+ await _create_setup_users(setup, auth_db_path)
1246
+
1247
+ # Reload user cache in APIAuthService to pick up newly created users
1248
+ auth_service = getattr(request.app.state, "auth_service", None)
1249
+ if auth_service:
1250
+ logger.info("Reloading user cache after setup user creation...")
1251
+ await auth_service.reload_users_from_db()
1252
+ logger.info("✅ User cache reloaded - new users now visible to authentication")
1253
+
1254
+ # Build next steps message
1255
+ next_steps = "Configuration completed. The agent is now starting. You can log in immediately."
1256
+ if setup.system_admin_password:
1257
+ next_steps += " Both user passwords have been configured."
1258
+
1259
+ # Resume initialization from first-run mode to start agent processor
1260
+ logger.info("Setup complete - resuming initialization to start agent processor")
1261
+ # Schedule resume in background to allow response to be sent first
1262
+ import asyncio
1263
+
1264
+ # Set resume flag AND timestamp BEFORE scheduling task to prevent SmartStartup from killing us
1265
+ # This flag blocks local-shutdown requests during the resume sequence
1266
+ # The timestamp enables timeout detection for stuck resume scenarios
1267
+ runtime._resume_in_progress = True
1268
+ runtime._resume_started_at = time.time()
1269
+ logger.info(f"[Setup] Set _resume_in_progress=True, _resume_started_at={runtime._resume_started_at:.3f}")
1270
+
1271
+ async def _resume_runtime() -> None:
1272
+ await asyncio.sleep(0.5) # Brief delay to ensure response is sent
1273
+ try:
1274
+ await runtime.resume_from_first_run()
1275
+ logger.info("✅ Successfully resumed from first-run mode - agent processor running")
1276
+ except Exception as e:
1277
+ logger.error(f"Failed to resume from first-run: {e}", exc_info=True)
1278
+ # Clear the flag and timestamp so shutdown can proceed
1279
+ runtime._resume_in_progress = False
1280
+ runtime._resume_started_at = None
1281
+ logger.info("[Setup] Cleared _resume_in_progress due to error")
1282
+ # If resume fails, fall back to restart
1283
+ runtime.request_shutdown("Resume failed - restarting to apply configuration")
1284
+
1285
+ # Store task to prevent garbage collection and log task creation
1286
+ resume_task = asyncio.create_task(_resume_runtime())
1287
+ logger.info(f"Scheduled background resume task: {resume_task.get_name()}")
1288
+
1289
+ return SuccessResponse(
1290
+ data={
1291
+ "status": "completed",
1292
+ "message": "Setup completed successfully. Starting agent processor...",
1293
+ "config_path": str(config_path),
1294
+ "username": setup.admin_username,
1295
+ "next_steps": next_steps,
1296
+ }
1297
+ )
1298
+
1299
+ except Exception as e:
1300
+ logger.error(f"Setup completion failed: {e}", exc_info=True)
1301
+ raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
1302
+
1303
+
1304
+ @router.get("/config", response_model=SuccessResponse[SetupConfigResponse])
1305
+ async def get_current_config(request: Request) -> SuccessResponse[SetupConfigResponse]:
1306
+ """Get current configuration.
1307
+
1308
+ Returns current setup configuration for editing.
1309
+ Requires authentication if setup is already completed.
1310
+ """
1311
+ # If not first-run, require authentication
1312
+ if not _is_setup_allowed_without_auth():
1313
+ # Manually get auth context from request
1314
+ try:
1315
+ from ..dependencies.auth import get_auth_context
1316
+
1317
+ auth = await get_auth_context(request)
1318
+ if auth is None:
1319
+ raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Authentication required")
1320
+ except HTTPException:
1321
+ raise
1322
+ except Exception:
1323
+ raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Authentication required")
1324
+
1325
+ # Read current config from environment
1326
+ config = SetupConfigResponse(
1327
+ llm_provider="openai" if os.getenv("OPENAI_API_BASE") is None else "other",
1328
+ llm_base_url=os.getenv("OPENAI_API_BASE"),
1329
+ llm_model=os.getenv("OPENAI_MODEL"),
1330
+ llm_api_key_set=bool(os.getenv("OPENAI_API_KEY")),
1331
+ backup_llm_base_url=os.getenv("CIRIS_OPENAI_API_BASE_2"),
1332
+ backup_llm_model=os.getenv("CIRIS_OPENAI_MODEL_NAME_2"),
1333
+ backup_llm_api_key_set=bool(os.getenv("CIRIS_OPENAI_API_KEY_2")),
1334
+ template_id=os.getenv("CIRIS_TEMPLATE", "general"),
1335
+ enabled_adapters=os.getenv("CIRIS_ADAPTER", "api").split(","),
1336
+ agent_port=int(os.getenv("CIRIS_API_PORT", "8080")),
1337
+ )
1338
+
1339
+ return SuccessResponse(data=config)
1340
+
1341
+
1342
+ @router.put("/config", response_model=SuccessResponse[Dict[str, str]])
1343
+ async def update_config(
1344
+ setup: SetupCompleteRequest, auth: AuthContext = Depends(get_auth_context)
1345
+ ) -> SuccessResponse[Dict[str, str]]:
1346
+ """Update configuration.
1347
+
1348
+ Updates setup configuration after initial setup.
1349
+ Requires admin authentication.
1350
+ """
1351
+ # Check for admin role
1352
+ from ciris_engine.schemas.api.auth import UserRole
1353
+
1354
+ if auth.role.level < UserRole.ADMIN.level:
1355
+ raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Admin role required")
1356
+
1357
+ try:
1358
+ # Get config path
1359
+ config_path = get_default_config_path()
1360
+
1361
+ # Save updated configuration
1362
+ _save_setup_config(setup, config_path)
1363
+
1364
+ return SuccessResponse(
1365
+ data={
1366
+ "status": "updated",
1367
+ "message": "Configuration updated successfully",
1368
+ "config_path": str(config_path),
1369
+ "next_steps": "Restart the agent to apply changes",
1370
+ }
1371
+ )
1372
+
1373
+ except Exception as e:
1374
+ raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))