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,1256 @@
1
+ """
2
+ Consent Service - FAIL FAST, FAIL LOUD, NO FAKE DATA.
3
+
4
+ Governance Service #5: Manages user consent for the Consensual Evolution Protocol.
5
+ Default: TEMPORARY (14 days) unless explicitly changed.
6
+ This is the 22nd core CIRIS service.
7
+
8
+ REFACTORED: Now uses modular architecture with separate modules for:
9
+ - exceptions: Custom errors
10
+ - metrics: Metrics collection
11
+ - partnership: Partnership management
12
+ - decay: Decay protocol
13
+ """
14
+
15
+ import logging
16
+ from datetime import datetime, timedelta, timezone
17
+ from typing import Any, Dict, List, Optional
18
+ from uuid import uuid4
19
+
20
+ from ciris_engine.logic.buses.memory_bus import MemoryBus
21
+ from ciris_engine.logic.persistence import add_graph_node, get_graph_node
22
+ from ciris_engine.logic.services.base_service import BaseService
23
+ from ciris_engine.logic.utils.jsondict_helpers import get_dict, get_float, get_list, get_str, get_str_optional
24
+ from ciris_engine.protocols.consent import ConsentManagerProtocol
25
+ from ciris_engine.protocols.services import ToolService
26
+ from ciris_engine.protocols.services.lifecycle.time import TimeServiceProtocol
27
+ from ciris_engine.schemas.adapters.tools import ToolExecutionResult, ToolExecutionStatus, ToolInfo, ToolParameterSchema
28
+ from ciris_engine.schemas.consent.core import (
29
+ ConsentAuditEntry,
30
+ ConsentCategory,
31
+ ConsentDecayStatus,
32
+ ConsentImpactReport,
33
+ ConsentRequest,
34
+ ConsentStatus,
35
+ ConsentStream,
36
+ )
37
+ from ciris_engine.schemas.runtime.enums import ServiceType
38
+ from ciris_engine.schemas.services.core import ServiceCapabilities
39
+ from ciris_engine.schemas.services.graph.memory import MemorySearchFilter
40
+ from ciris_engine.schemas.services.graph_core import GraphNode, GraphScope, NodeType
41
+ from ciris_engine.schemas.types import JSONDict
42
+
43
+ # Import from new modules
44
+ from .air import ArtificialInteractionReminder
45
+ from .decay import DecayProtocolManager
46
+ from .exceptions import ConsentNotFoundError, ConsentValidationError
47
+ from .metrics import ConsentMetricsCollector
48
+ from .partnership import PartnershipManager
49
+
50
+ logger = logging.getLogger(__name__)
51
+
52
+
53
+ class ConsentService(BaseService, ConsentManagerProtocol, ToolService):
54
+ """
55
+ Consent Service - 22nd Core CIRIS Service (Governance #5).
56
+
57
+ Manages user consent with HARD GUARANTEES:
58
+ - TEMPORARY by default (14 days)
59
+ - No fake data or fallbacks
60
+ - Immutable audit trail
61
+ - Real decay protocol
62
+ - Bilateral agreement for PARTNERED
63
+ """
64
+
65
+ def __init__(
66
+ self,
67
+ time_service: TimeServiceProtocol,
68
+ memory_bus: Optional[MemoryBus] = None,
69
+ db_path: Optional[str] = None,
70
+ ):
71
+ super().__init__(time_service=time_service, service_name="ConsentService")
72
+ self._time_service = time_service
73
+ self._memory_bus = memory_bus
74
+ self._db_path = db_path
75
+
76
+ # Initialize modular managers
77
+ self._metrics_collector = ConsentMetricsCollector()
78
+ self._partnership_manager = PartnershipManager(time_service=time_service)
79
+ self._decay_manager = DecayProtocolManager(time_service=time_service, db_path=db_path)
80
+ self._air_manager = ArtificialInteractionReminder(
81
+ time_service=time_service,
82
+ time_threshold_minutes=30, # 30 minutes
83
+ message_threshold=20, # 20 messages
84
+ )
85
+
86
+ # Cache for active consents (NOT source of truth)
87
+ self._consent_cache: Dict[str, ConsentStatus] = {}
88
+
89
+ # Core Metrics (real, no fake data)
90
+ self._consent_checks = 0
91
+ self._consent_grants = 0
92
+ self._consent_revokes = 0
93
+ self._tool_executions = 0
94
+ self._tool_failures = 0
95
+ self._expired_cleanups = 0
96
+
97
+ # Downgrade tracking
98
+ self._downgrades_completed = 0
99
+
100
+ def _now(self) -> datetime:
101
+ """Get current time from time service."""
102
+ if self._time_service is None:
103
+ return datetime.now(timezone.utc)
104
+ return self._time_service.now()
105
+
106
+ async def _extend_temporary_expiry(self, user_id: str, status: ConsentStatus) -> None:
107
+ """
108
+ Reset TEMPORARY expiry to 2 weeks from now on every interaction.
109
+ This implements the "2 weeks without seeing them before decay" rule.
110
+ """
111
+ now = self._now()
112
+ new_expiry = now + timedelta(days=14)
113
+
114
+ # Only update if expiry changed significantly (avoid unnecessary writes)
115
+ if status.expires_at and (new_expiry - status.expires_at).total_seconds() < 3600:
116
+ # Less than 1 hour difference, skip update to reduce I/O
117
+ return
118
+
119
+ # Update status with new expiry
120
+ status.expires_at = new_expiry
121
+ status.last_modified = now
122
+
123
+ # Persist to graph
124
+ node = GraphNode(
125
+ id=f"consent/{user_id}",
126
+ type=NodeType.CONSENT,
127
+ scope=GraphScope.LOCAL,
128
+ attributes={
129
+ "stream": status.stream,
130
+ "categories": list(status.categories),
131
+ "granted_at": status.granted_at.isoformat(),
132
+ "expires_at": new_expiry.isoformat(),
133
+ "last_modified": now.isoformat(),
134
+ "impact_score": status.impact_score,
135
+ "attribution_count": status.attribution_count,
136
+ },
137
+ updated_by="consent_manager",
138
+ updated_at=now,
139
+ )
140
+ if self._time_service is None:
141
+ raise ValueError("TimeService required for extending expiry")
142
+ add_graph_node(node, self._time_service, self._db_path)
143
+
144
+ # Update cache
145
+ self._consent_cache[user_id] = status
146
+
147
+ logger.debug(f"Extended TEMPORARY expiry for {user_id} to {new_expiry.isoformat()}")
148
+
149
+ def _check_cached_expiry(self, user_id: str, cached: ConsentStatus) -> None:
150
+ """Check if cached consent has expired and remove if so."""
151
+ if cached.stream == ConsentStream.TEMPORARY and cached.expires_at:
152
+ if self._now() > cached.expires_at:
153
+ del self._consent_cache[user_id]
154
+ raise ConsentNotFoundError(f"Consent for {user_id} has expired")
155
+
156
+ def _reconstruct_consent_from_node(self, user_id: str, node: Any) -> ConsentStatus:
157
+ """Reconstruct ConsentStatus from graph node."""
158
+ attrs = node.attributes if isinstance(node.attributes, dict) else node.attributes.model_dump()
159
+
160
+ # Extract expires_at separately to avoid walrus operator in argument list
161
+ expires_str = get_str_optional(attrs, "expires_at")
162
+ expires_at = datetime.fromisoformat(expires_str) if expires_str else None
163
+
164
+ return ConsentStatus(
165
+ user_id=user_id,
166
+ stream=ConsentStream(get_str(attrs, "stream", "temporary")),
167
+ categories=[ConsentCategory(c) for c in get_list(attrs, "categories", [])],
168
+ granted_at=datetime.fromisoformat(get_str(attrs, "granted_at", datetime.now(timezone.utc).isoformat())),
169
+ expires_at=expires_at,
170
+ last_modified=datetime.fromisoformat(
171
+ get_str(attrs, "last_modified", datetime.now(timezone.utc).isoformat())
172
+ ),
173
+ impact_score=get_float(attrs, "impact_score", 0.0),
174
+ attribution_count=int(get_float(attrs, "attribution_count", 0)),
175
+ )
176
+
177
+ async def _load_consent_from_graph(self, user_id: str) -> ConsentStatus:
178
+ """Load consent from graph storage."""
179
+ node = get_graph_node(f"consent/{user_id}", GraphScope.LOCAL, self._db_path)
180
+ if not node:
181
+ raise ConsentNotFoundError(f"No consent found for user {user_id}")
182
+
183
+ status = self._reconstruct_consent_from_node(user_id, node)
184
+
185
+ # Check expiry
186
+ if status.stream == ConsentStream.TEMPORARY and status.expires_at:
187
+ if self._now() > status.expires_at:
188
+ raise ConsentNotFoundError(f"Consent for {user_id} has expired")
189
+
190
+ # Update cache
191
+ self._consent_cache[user_id] = status
192
+ return status
193
+
194
+ async def get_consent(self, user_id: str, extend_expiry: bool = True) -> ConsentStatus:
195
+ """
196
+ Get user's consent status.
197
+ FAILS if user doesn't exist - NO DEFAULTS.
198
+
199
+ Args:
200
+ user_id: User ID to get consent for
201
+ extend_expiry: If True, reset TEMPORARY expiry to 2 weeks from now (default: True)
202
+ """
203
+ self._consent_checks += 1
204
+
205
+ # Try cache first (but verify it's still valid)
206
+ if user_id in self._consent_cache:
207
+ cached = self._consent_cache[user_id]
208
+ self._check_cached_expiry(user_id, cached)
209
+
210
+ # Reset decay countdown on every interaction (2 weeks without seeing them)
211
+ if extend_expiry and cached.stream == ConsentStream.TEMPORARY:
212
+ await self._extend_temporary_expiry(user_id, cached)
213
+
214
+ return cached
215
+
216
+ # Load from graph
217
+ try:
218
+ status = await self._load_consent_from_graph(user_id)
219
+
220
+ # Reset decay countdown on every interaction (2 weeks without seeing them)
221
+ if extend_expiry and status.stream == ConsentStream.TEMPORARY:
222
+ await self._extend_temporary_expiry(user_id, status)
223
+
224
+ return status
225
+
226
+ except Exception as e:
227
+ if "not found" in str(e).lower():
228
+ raise ConsentNotFoundError(f"No consent found for user {user_id}")
229
+ raise
230
+
231
+ async def track_interaction(
232
+ self, user_id: str, channel_id: str, channel_type: Optional[str] = None, message_content: Optional[str] = None
233
+ ) -> Optional[str]:
234
+ """
235
+ Track user interaction for parasocial attachment prevention.
236
+
237
+ This method delegates to the AIR (Artificial Interaction Reminder) manager
238
+ to monitor 1:1 API interactions and provide break reminders when thresholds are exceeded.
239
+
240
+ Scope: API channels only (1:1 interactions, not community moderation)
241
+ Triggers:
242
+ - 30 minutes continuous interaction
243
+ - 20+ messages
244
+ - High valence patterns (anthropomorphism, dependency, emotional intensity)
245
+
246
+ Args:
247
+ user_id: User ID
248
+ channel_id: Channel ID
249
+ channel_type: Channel type (api, discord, cli, unknown) - if None, will infer from ID
250
+ message_content: Optional message content for valence analysis
251
+
252
+ Returns:
253
+ Reminder message if threshold exceeded, None otherwise
254
+ """
255
+ return self._air_manager.track_interaction(user_id, channel_id, channel_type, message_content)
256
+
257
+ async def grant_consent(self, request: ConsentRequest, channel_id: Optional[str] = None) -> ConsentStatus:
258
+ """
259
+ Grant or update consent.
260
+ VALIDATES everything, creates audit trail.
261
+
262
+ PARTNERED requires bilateral agreement:
263
+ - Creates task for agent approval
264
+ - Agent can REJECT, DEFER, or TASK_COMPLETE (accept)
265
+ - Returns pending status until agent decides
266
+ """
267
+ self._consent_grants += 1
268
+
269
+ # Validate request
270
+ self._validate_consent_request(request)
271
+
272
+ # Get previous status if exists
273
+ previous_status = await self._get_previous_status(request.user_id)
274
+
275
+ # Check if upgrading to PARTNERED - requires bilateral agreement
276
+ if request.stream == ConsentStream.PARTNERED:
277
+ return await self._partnership_manager.create_partnership_request(request, previous_status, channel_id)
278
+
279
+ # Check for gaming behavior if switching streams
280
+ await self._check_gaming_behavior(request, previous_status)
281
+
282
+ # For TEMPORARY and ANONYMOUS - no bilateral agreement needed
283
+ new_status = self._create_consent_status(request, previous_status)
284
+
285
+ # Persist consent and audit trail
286
+ await self._persist_consent(new_status, previous_status, request.reason, "user")
287
+
288
+ logger.info(f"Consent granted for {request.user_id}: {new_status.stream}")
289
+ return new_status
290
+
291
+ def _validate_consent_request(self, request: ConsentRequest) -> None:
292
+ """Validate consent request parameters."""
293
+ if not request.user_id:
294
+ raise ConsentValidationError("User ID required")
295
+ if not request.categories and request.stream == ConsentStream.PARTNERED:
296
+ raise ConsentValidationError("PARTNERED requires at least one category")
297
+
298
+ async def _get_previous_status(self, user_id: str) -> Optional[ConsentStatus]:
299
+ """Get previous consent status if exists."""
300
+ try:
301
+ return await self.get_consent(user_id)
302
+ except ConsentNotFoundError:
303
+ return None
304
+
305
+ async def _check_gaming_behavior(self, request: ConsentRequest, previous_status: Optional[ConsentStatus]) -> None:
306
+ """Check for gaming behavior if switching consent streams."""
307
+ if not previous_status or request.stream == previous_status.stream:
308
+ return
309
+
310
+ if not hasattr(self, "_filter_service"):
311
+ return
312
+
313
+ # Handle both enum and string types for stream
314
+ prev_stream = (
315
+ previous_status.stream.value if hasattr(previous_status.stream, "value") else previous_status.stream
316
+ )
317
+ req_stream = request.stream.value if hasattr(request.stream, "value") else request.stream
318
+
319
+ is_gaming = await self._filter_service.handle_consent_transition(request.user_id, prev_stream, req_stream)
320
+
321
+ if is_gaming:
322
+ logger.warning(
323
+ f"Gaming attempt detected for {request.user_id}: {previous_status.stream} -> {request.stream}"
324
+ )
325
+
326
+ def _create_consent_status(
327
+ self, request: ConsentRequest, previous_status: Optional[ConsentStatus]
328
+ ) -> ConsentStatus:
329
+ """Create new consent status from request."""
330
+ now = self._now()
331
+ expires_at = None
332
+ if request.stream == ConsentStream.TEMPORARY:
333
+ expires_at = now + timedelta(days=14)
334
+
335
+ return ConsentStatus(
336
+ user_id=request.user_id,
337
+ stream=request.stream,
338
+ categories=request.categories,
339
+ granted_at=previous_status.granted_at if previous_status else now,
340
+ expires_at=expires_at,
341
+ last_modified=now,
342
+ impact_score=previous_status.impact_score if previous_status else 0.0,
343
+ attribution_count=previous_status.attribution_count if previous_status else 0,
344
+ )
345
+
346
+ async def _persist_consent(
347
+ self,
348
+ new_status: ConsentStatus,
349
+ previous_status: Optional[ConsentStatus],
350
+ reason: Optional[str],
351
+ initiated_by: str,
352
+ ) -> None:
353
+ """Persist consent status and audit trail to graph."""
354
+ now = self._now()
355
+
356
+ # Store in graph
357
+ node = GraphNode(
358
+ id=f"consent/{new_status.user_id}",
359
+ type=NodeType.CONSENT,
360
+ scope=GraphScope.LOCAL,
361
+ attributes={
362
+ "stream": new_status.stream,
363
+ "categories": list(new_status.categories),
364
+ "granted_at": new_status.granted_at.isoformat(),
365
+ "expires_at": new_status.expires_at.isoformat() if new_status.expires_at else None,
366
+ "last_modified": new_status.last_modified.isoformat(),
367
+ "impact_score": new_status.impact_score,
368
+ "attribution_count": new_status.attribution_count,
369
+ },
370
+ updated_by="consent_manager",
371
+ updated_at=now,
372
+ )
373
+ if self._time_service is None:
374
+ raise ValueError("TimeService required for persisting consent")
375
+ add_graph_node(node, self._time_service, self._db_path)
376
+
377
+ # Create audit entry
378
+ audit = ConsentAuditEntry(
379
+ entry_id=str(uuid4()),
380
+ user_id=new_status.user_id,
381
+ timestamp=now,
382
+ previous_stream=previous_status.stream if previous_status else ConsentStream.TEMPORARY,
383
+ new_stream=new_status.stream,
384
+ previous_categories=previous_status.categories if previous_status else [],
385
+ new_categories=new_status.categories,
386
+ initiated_by=initiated_by,
387
+ reason=reason,
388
+ )
389
+
390
+ # Store audit entry
391
+ audit_attrs = audit.model_dump(mode="json")
392
+ audit_attrs["service"] = "consent" # Add service identifier for querying
393
+ audit_node = GraphNode(
394
+ id=f"consent_audit/{audit.entry_id}",
395
+ type=NodeType.AUDIT_ENTRY,
396
+ scope=GraphScope.IDENTITY, # Use IDENTITY scope for user-specific audit trail
397
+ attributes=audit_attrs,
398
+ updated_by="consent_manager",
399
+ updated_at=now,
400
+ )
401
+ add_graph_node(audit_node, self._time_service, self._db_path)
402
+
403
+ # Update cache
404
+ self._consent_cache[new_status.user_id] = new_status
405
+
406
+ async def update_consent(
407
+ self, user_id: str, stream: ConsentStream, categories: List[ConsentCategory], reason: Optional[str] = None
408
+ ) -> ConsentStatus:
409
+ """
410
+ Internal method to update consent status directly.
411
+ Used by tool handlers for consent transitions.
412
+ Does NOT perform bilateral agreement checks - those should be done by caller.
413
+ """
414
+ # Get previous status if exists
415
+ previous_status = None
416
+ try:
417
+ previous_status = await self.get_consent(user_id)
418
+ except ConsentNotFoundError:
419
+ pass
420
+
421
+ now = self._now()
422
+ expires_at = None
423
+ if stream == ConsentStream.TEMPORARY:
424
+ expires_at = now + timedelta(days=14)
425
+
426
+ new_status = ConsentStatus(
427
+ user_id=user_id,
428
+ stream=stream,
429
+ categories=categories,
430
+ granted_at=previous_status.granted_at if previous_status else now,
431
+ expires_at=expires_at,
432
+ last_modified=now,
433
+ impact_score=previous_status.impact_score if previous_status else 0.0,
434
+ attribution_count=previous_status.attribution_count if previous_status else 0,
435
+ )
436
+
437
+ # Store in graph
438
+ node = GraphNode(
439
+ id=f"consent/{user_id}",
440
+ type=NodeType.CONSENT,
441
+ scope=GraphScope.LOCAL,
442
+ attributes={
443
+ "stream": new_status.stream,
444
+ "categories": list(new_status.categories),
445
+ "granted_at": new_status.granted_at.isoformat(),
446
+ "expires_at": new_status.expires_at.isoformat() if new_status.expires_at else None,
447
+ "last_modified": new_status.last_modified.isoformat(),
448
+ "impact_score": new_status.impact_score,
449
+ "attribution_count": new_status.attribution_count,
450
+ },
451
+ updated_by="consent_manager",
452
+ updated_at=now,
453
+ )
454
+
455
+ if self._time_service is None:
456
+ raise ValueError("TimeService required for updating consent")
457
+ add_graph_node(node, self._time_service, self._db_path)
458
+
459
+ # Create audit entry
460
+ audit = ConsentAuditEntry(
461
+ entry_id=str(uuid4()),
462
+ user_id=user_id,
463
+ timestamp=now,
464
+ previous_stream=previous_status.stream if previous_status else ConsentStream.TEMPORARY,
465
+ new_stream=new_status.stream,
466
+ previous_categories=previous_status.categories if previous_status else [],
467
+ new_categories=new_status.categories,
468
+ initiated_by="tool",
469
+ reason=reason or "Tool-initiated update",
470
+ )
471
+
472
+ # Store audit entry
473
+ audit_attrs = audit.model_dump(mode="json")
474
+ audit_attrs["service"] = "consent" # Add service identifier for querying
475
+ audit_node = GraphNode(
476
+ id=f"consent_audit/{audit.entry_id}",
477
+ type=NodeType.AUDIT_ENTRY,
478
+ scope=GraphScope.IDENTITY, # Use IDENTITY scope for user-specific audit trail
479
+ attributes=audit_attrs,
480
+ updated_by="consent_manager",
481
+ updated_at=now,
482
+ )
483
+ add_graph_node(audit_node, self._time_service, self._db_path)
484
+
485
+ # Update cache
486
+ self._consent_cache[user_id] = new_status
487
+
488
+ logger.info(f"Consent updated for {user_id}: {new_status.stream}")
489
+ return new_status
490
+
491
+ async def revoke_consent(self, user_id: str, reason: Optional[str] = None) -> ConsentDecayStatus:
492
+ """
493
+ Start decay protocol - IMMEDIATE identity severance.
494
+ Delegates to DecayProtocolManager for actual decay handling.
495
+ """
496
+ self._consent_revokes += 1
497
+
498
+ # Verify user exists
499
+ status = await self.get_consent(user_id)
500
+
501
+ # Get filter service if available
502
+ filter_service = self._filter_service if hasattr(self, "_filter_service") else None
503
+
504
+ # Delegate to decay manager
505
+ decay = await self._decay_manager.initiate_decay(
506
+ user_id=user_id,
507
+ reason=reason,
508
+ initiated_by="user",
509
+ current_status=status,
510
+ filter_service=filter_service,
511
+ )
512
+
513
+ # Remove from cache (decay manager handles persistence)
514
+ if user_id in self._consent_cache:
515
+ del self._consent_cache[user_id]
516
+
517
+ return decay
518
+
519
+ async def check_expiry(self, user_id: str) -> bool:
520
+ """
521
+ Check if TEMPORARY consent has expired.
522
+ NO GRACE PERIOD - expired means expired.
523
+
524
+ Returns:
525
+ False: Consent exists and is valid
526
+ True: Consent exists but is expired
527
+
528
+ Raises:
529
+ ConsentNotFoundError: User has no consent record (FAIL FAST)
530
+ """
531
+ status = await self.get_consent(user_id) # Let it raise - fail fast!
532
+ if status.stream == ConsentStream.TEMPORARY and status.expires_at:
533
+ return self._now() > status.expires_at
534
+ return False
535
+
536
+ async def get_impact_report(self, user_id: str) -> ConsentImpactReport:
537
+ """
538
+ Generate impact report - REAL DATA ONLY.
539
+ """
540
+ # Get consent status first
541
+ status = await self.get_consent(user_id)
542
+
543
+ # Query REAL data from TSDB summaries - NO FALLBACKS
544
+ if not self._memory_bus:
545
+ raise ValueError("Memory bus required for impact reporting - no fake data allowed")
546
+
547
+ # Get real interaction data from TSDB conversation summaries
548
+ conversation_summaries = await self._memory_bus.search(
549
+ query="", # Empty query to get all matching nodes
550
+ filters=MemorySearchFilter(node_type=NodeType.CONVERSATION_SUMMARY.value, scope=GraphScope.COMMUNITY.value),
551
+ )
552
+
553
+ # Count interactions where this user participated
554
+ total_interactions = 0
555
+ for summary in conversation_summaries:
556
+ if summary.attributes:
557
+ attrs = summary.attributes if isinstance(summary.attributes, dict) else summary.attributes.model_dump()
558
+ if "participants" in attrs:
559
+ participants = attrs["participants"]
560
+ # Check if user_id is in any participant data
561
+ if isinstance(participants, dict):
562
+ for participant_data in participants.values():
563
+ if isinstance(participant_data, dict) and participant_data.get("user_id") == user_id:
564
+ total_interactions += participant_data.get("message_count", 0)
565
+
566
+ # Get real contribution data from task summaries
567
+ task_summaries = await self._memory_bus.search(
568
+ query="", filters=MemorySearchFilter(node_type=NodeType.TASK_SUMMARY.value, scope=GraphScope.IDENTITY.value)
569
+ )
570
+
571
+ patterns_contributed = 0
572
+ for task_summary in task_summaries:
573
+ if task_summary.attributes:
574
+ attrs = (
575
+ task_summary.attributes
576
+ if isinstance(task_summary.attributes, dict)
577
+ else task_summary.attributes.model_dump()
578
+ )
579
+ if attrs.get("author_id") == user_id:
580
+ patterns_contributed += 1
581
+
582
+ # Calculate users helped from actual conversation engagement
583
+ users_helped_set = set()
584
+ for summary in conversation_summaries:
585
+ if summary.attributes:
586
+ attrs = summary.attributes if isinstance(summary.attributes, dict) else summary.attributes.model_dump()
587
+ if "participants" in attrs and isinstance(attrs["participants"], dict):
588
+ for participant_id, participant_data in attrs["participants"].items():
589
+ if participant_id != user_id and isinstance(participant_data, dict):
590
+ users_helped_set.add(participant_id)
591
+ users_helped = len(users_helped_set)
592
+
593
+ logger.info(
594
+ f"Real impact metrics for {user_id}: {total_interactions} interactions, {patterns_contributed} contributions, {users_helped} users helped"
595
+ )
596
+
597
+ report = ConsentImpactReport(
598
+ user_id=user_id,
599
+ total_interactions=total_interactions,
600
+ patterns_contributed=patterns_contributed,
601
+ users_helped=users_helped,
602
+ categories_active=status.categories,
603
+ impact_score=status.impact_score,
604
+ example_contributions=await self._get_example_contributions(user_id),
605
+ )
606
+
607
+ return report
608
+
609
+ async def get_audit_trail(self, user_id: str, limit: int = 100) -> List[ConsentAuditEntry]:
610
+ """
611
+ Get consent change history - IMMUTABLE AUDIT TRAIL.
612
+ """
613
+ # Query consent audit entries from graph
614
+ audit_entries = []
615
+
616
+ if self._memory_bus:
617
+ try:
618
+ # Query audit nodes for this user
619
+ audit_nodes = await self._memory_bus.search(
620
+ query="",
621
+ filters=MemorySearchFilter(
622
+ node_type=NodeType.AUDIT_ENTRY.value,
623
+ scope=GraphScope.IDENTITY.value,
624
+ attribute_values={"user_id": user_id, "service": "consent"},
625
+ ),
626
+ )
627
+
628
+ # Convert nodes to audit entries (limit by parameter)
629
+ for node in audit_nodes[:limit]:
630
+ if node.attributes:
631
+ attrs = node.attributes if isinstance(node.attributes, dict) else node.attributes.model_dump()
632
+ entry = ConsentAuditEntry(
633
+ entry_id=get_str(attrs, "entry_id", "unknown"),
634
+ user_id=user_id,
635
+ timestamp=node.updated_at,
636
+ previous_stream=ConsentStream(get_str(attrs, "previous_stream", "temporary")),
637
+ new_stream=ConsentStream(get_str(attrs, "new_stream", "temporary")),
638
+ previous_categories=[
639
+ ConsentCategory(c) for c in get_list(attrs, "previous_categories", [])
640
+ ],
641
+ new_categories=[ConsentCategory(c) for c in get_list(attrs, "new_categories", [])],
642
+ initiated_by=get_str(attrs, "initiated_by", "unknown"),
643
+ reason=get_str_optional(attrs, "reason"),
644
+ )
645
+ audit_entries.append(entry)
646
+
647
+ logger.debug(f"Found {len(audit_entries)} audit entries for {user_id}")
648
+ except Exception as e:
649
+ logger.warning(f"Failed to query audit trail for {user_id}: {e}")
650
+
651
+ return audit_entries
652
+
653
+ async def check_pending_partnership(self, user_id: str) -> Optional[str]:
654
+ """
655
+ Check status of pending partnership request.
656
+ Delegates to PartnershipManager for checking and finalization.
657
+
658
+ Returns:
659
+ - "accepted": Partnership approved by agent
660
+ - "rejected": Partnership declined by agent
661
+ - "deferred": Agent needs more information
662
+ - "pending": Still processing
663
+ - None: No pending request
664
+ """
665
+ # Check status via partnership manager
666
+ status = await self._partnership_manager.check_partnership_status(user_id)
667
+
668
+ # If not accepted, return the status as-is
669
+ if status != "accepted":
670
+ return status
671
+
672
+ # Partnership was accepted - finalize it
673
+ # Get task_id from pending partnerships
674
+ pending_list = self._partnership_manager.list_pending_partnerships()
675
+ task_id = None
676
+ for pending in pending_list:
677
+ if pending.get("user_id") == user_id:
678
+ task_id = pending.get("task_id")
679
+ break
680
+
681
+ if not task_id:
682
+ logger.warning(f"Partnership accepted for {user_id} but no task_id found")
683
+ return status
684
+
685
+ # Finalize via partnership manager
686
+ partnership_data = self._partnership_manager.finalize_partnership_approval(user_id, str(task_id))
687
+
688
+ if not partnership_data:
689
+ logger.warning(f"Partnership finalization failed for {user_id}")
690
+ return status
691
+
692
+ # Create and persist PARTNERED consent status
693
+ now = self._now()
694
+ categories = partnership_data.get("categories", [])
695
+
696
+ partnered_status = ConsentStatus(
697
+ user_id=user_id,
698
+ stream=ConsentStream.PARTNERED,
699
+ categories=categories,
700
+ granted_at=now,
701
+ expires_at=None, # PARTNERED doesn't expire
702
+ last_modified=now,
703
+ impact_score=0.0,
704
+ attribution_count=0,
705
+ )
706
+
707
+ # Store in graph
708
+ node = GraphNode(
709
+ id=f"consent/{user_id}",
710
+ type=NodeType.CONSENT,
711
+ scope=GraphScope.LOCAL,
712
+ attributes={
713
+ "stream": partnered_status.stream,
714
+ "categories": list(partnered_status.categories),
715
+ "granted_at": partnered_status.granted_at.isoformat(),
716
+ "expires_at": None,
717
+ "last_modified": partnered_status.last_modified.isoformat(),
718
+ "impact_score": partnered_status.impact_score,
719
+ "attribution_count": partnered_status.attribution_count,
720
+ "partnership_approved": True,
721
+ "approval_task_id": task_id,
722
+ },
723
+ updated_by="consent_manager",
724
+ updated_at=now,
725
+ )
726
+
727
+ if self._time_service is None:
728
+ raise ValueError("TimeService required for finalizing partnership")
729
+ add_graph_node(node, self._time_service, self._db_path)
730
+
731
+ # Update cache
732
+ self._consent_cache[user_id] = partnered_status
733
+
734
+ # Return "partnered" to indicate successful finalization (different from "accepted")
735
+ return "partnered"
736
+
737
+ async def _get_example_contributions(self, user_id: str) -> List[str]:
738
+ """Get example contributions from the graph."""
739
+ examples: List[str] = []
740
+
741
+ if self._memory_bus:
742
+ try:
743
+ # Query recent contribution nodes from this user
744
+ contribution_nodes = await self._memory_bus.search(
745
+ query="",
746
+ filters=MemorySearchFilter(
747
+ node_type=NodeType.CONCEPT.value,
748
+ scope=GraphScope.COMMUNITY.value,
749
+ attribute_values={"contributor_id": user_id},
750
+ ),
751
+ )
752
+
753
+ # Extract meaningful examples (limit to 3-5)
754
+ for node in contribution_nodes[:5]:
755
+ if node.attributes:
756
+ attrs = node.attributes if isinstance(node.attributes, dict) else node.attributes.model_dump()
757
+ # Use get_str to extract string values safely
758
+ description = get_str_optional(attrs, "description")
759
+ if description:
760
+ examples.append(description)
761
+ else:
762
+ content = get_str_optional(attrs, "content")
763
+ if content:
764
+ examples.append(content)
765
+ else:
766
+ # Fallback to node ID if no meaningful description
767
+ examples.append(f"Contribution: {node.id}")
768
+
769
+ logger.debug(f"Found {len(examples)} example contributions for {user_id}")
770
+ except Exception as e:
771
+ logger.warning(f"Failed to query example contributions for {user_id}: {e}")
772
+
773
+ # Fallback examples if no graph data
774
+ if not examples:
775
+ examples = [
776
+ "Provided feedback on system behavior",
777
+ "Contributed to pattern recognition",
778
+ "Participated in conversation threads",
779
+ ]
780
+
781
+ return examples
782
+
783
+ async def cleanup_expired(self) -> int:
784
+ """
785
+ Clean up all expired TEMPORARY consents.
786
+ HARD DELETE after 14 days.
787
+ """
788
+ self._expired_cleanups += 1
789
+ current_time = self._now()
790
+
791
+ # Get expired user IDs from graph or cache
792
+ expired_user_ids = await self._find_expired_user_ids(current_time)
793
+
794
+ # Perform cleanup operations
795
+ cleanup_count = self._perform_cleanup(expired_user_ids)
796
+
797
+ return cleanup_count
798
+
799
+ async def _find_expired_user_ids(self, current_time: datetime) -> List[str]:
800
+ """Find all user IDs with expired temporary consents."""
801
+ if self._memory_bus:
802
+ return await self._find_expired_from_graph(current_time)
803
+ else:
804
+ return self._find_expired_from_cache(current_time)
805
+
806
+ async def _find_expired_from_graph(self, current_time: datetime) -> List[str]:
807
+ """Find expired consents from memory graph nodes."""
808
+ expired = []
809
+
810
+ if self._memory_bus is None:
811
+ return []
812
+
813
+ try:
814
+ consent_nodes = await self._memory_bus.search(
815
+ query="",
816
+ filters=MemorySearchFilter(
817
+ node_type=NodeType.CONCEPT.value,
818
+ scope=GraphScope.IDENTITY.value,
819
+ attribute_values={"service": "consent"},
820
+ ),
821
+ )
822
+
823
+ for node in consent_nodes:
824
+ user_id = self._extract_expired_user_from_node(node, current_time)
825
+ if user_id:
826
+ expired.append(user_id)
827
+
828
+ logger.debug(f"Found {len(expired)} expired consent nodes in graph")
829
+
830
+ except Exception as e:
831
+ logger.warning(f"Failed to query consent nodes for expiry cleanup: {e}")
832
+ # Fall back to cache-based cleanup on graph query failure
833
+ expired = self._find_expired_from_cache(current_time)
834
+
835
+ return expired
836
+
837
+ def _extract_expired_user_from_node(self, node: Any, current_time: datetime) -> Optional[str]:
838
+ """Extract user ID if the consent node represents an expired temporary consent."""
839
+ if not node.attributes:
840
+ return None
841
+
842
+ attrs = node.attributes if isinstance(node.attributes, dict) else node.attributes.model_dump()
843
+ stream = attrs.get("stream")
844
+ expires_at_str = attrs.get("expires_at")
845
+ user_id = attrs.get("user_id")
846
+
847
+ # Check if this is a temporary consent with expiry data
848
+ if not (stream == ConsentStream.TEMPORARY.value and expires_at_str and user_id):
849
+ return None
850
+
851
+ # Parse and check expiry
852
+ try:
853
+ expires_at = datetime.fromisoformat(expires_at_str)
854
+ if current_time > expires_at:
855
+ return str(user_id)
856
+ except Exception as e:
857
+ logger.warning(f"Failed to parse expiry date for {user_id}: {e}")
858
+
859
+ return None
860
+
861
+ def _find_expired_from_cache(self, current_time: datetime) -> List[str]:
862
+ """Find expired consents from local cache as fallback."""
863
+ expired = []
864
+
865
+ for user_id, status in self._consent_cache.items():
866
+ if self._is_cache_entry_expired(status, current_time):
867
+ expired.append(user_id)
868
+
869
+ return expired
870
+
871
+ def _is_cache_entry_expired(self, status: ConsentStatus, current_time: datetime) -> bool:
872
+ """Check if a cached consent status is expired."""
873
+ return (
874
+ status.stream == ConsentStream.TEMPORARY
875
+ and status.expires_at is not None
876
+ and current_time > status.expires_at
877
+ )
878
+
879
+ def _perform_cleanup(self, expired_user_ids: List[str]) -> int:
880
+ """Remove expired consents from cache and return count."""
881
+ count = 0
882
+
883
+ for user_id in expired_user_ids:
884
+ if user_id in self._consent_cache:
885
+ del self._consent_cache[user_id]
886
+ count += 1
887
+ logger.info(f"Cleaned up expired consent for {user_id}")
888
+
889
+ return count
890
+
891
+ def get_service_type(self) -> ServiceType:
892
+ """Get service type."""
893
+ return ServiceType.TOOL # Changed to TOOL so it can be discovered by ToolBus
894
+
895
+ def get_capabilities(self) -> ServiceCapabilities:
896
+ """Get service capabilities."""
897
+ return ServiceCapabilities(
898
+ service_name="ConsentService",
899
+ actions=[], # Non-bussed services don't have actions
900
+ version="0.2.0",
901
+ dependencies=["TimeService"],
902
+ metadata=None,
903
+ )
904
+
905
+ def _extract_air_metrics(self, air_metrics: Dict[str, Any]) -> Dict[str, float]:
906
+ """Extract and safely cast AIR metrics."""
907
+ return {
908
+ "consent_air_total_interactions": (
909
+ float(val) if isinstance((val := air_metrics.get("total_interactions", 0)), (int, float)) else 0.0
910
+ ),
911
+ "consent_air_reminders_sent": (
912
+ float(val) if isinstance((val := air_metrics.get("reminders_sent", 0)), (int, float)) else 0.0
913
+ ),
914
+ "consent_air_reminder_rate_percent": (
915
+ float(val) if isinstance((val := air_metrics.get("reminder_rate_percent", 0.0)), (int, float)) else 0.0
916
+ ),
917
+ "consent_air_active_sessions": (
918
+ float(val) if isinstance((val := air_metrics.get("active_sessions", 0)), (int, float)) else 0.0
919
+ ),
920
+ "consent_air_time_triggered": (
921
+ float(val) if isinstance((val := air_metrics.get("time_triggered_reminders", 0)), (int, float)) else 0.0
922
+ ),
923
+ "consent_air_message_triggered": (
924
+ float(val)
925
+ if isinstance((val := air_metrics.get("message_triggered_reminders", 0)), (int, float))
926
+ else 0.0
927
+ ),
928
+ }
929
+
930
+ def _collect_custom_metrics(self) -> Dict[str, float]:
931
+ """
932
+ Collect consent-specific metrics - REAL DATA ONLY.
933
+
934
+ Top 5 Most Important Metrics:
935
+ 1. consent_active_users - Number of users with active consent
936
+ 2. consent_stream_distribution - Breakdown by stream type (TEMPORARY/PARTNERED/ANONYMOUS)
937
+ 3. consent_partnership_success_rate - Approval rate for partnership requests
938
+ 4. consent_average_age_days - Average age of active consents
939
+ 5. consent_decay_completion_rate - Percentage of decays completed vs initiated
940
+ """
941
+ # Get base metrics from parent
942
+ metrics = super()._collect_custom_metrics()
943
+
944
+ now = self._time_service.now() if self._time_service else datetime.now(timezone.utc)
945
+
946
+ # Collect stream distribution metrics using metrics collector
947
+ stream_metrics = self._metrics_collector.collect_stream_distribution(self._consent_cache, now)
948
+ metrics.update(stream_metrics)
949
+
950
+ # Get partnership metrics from manager
951
+ partnership_requests, partnership_approvals, _ = self._partnership_manager.get_request_counts()
952
+ partnership_metrics = self._metrics_collector.collect_partnership_metrics(
953
+ partnership_requests, partnership_approvals, 0, self._partnership_manager.get_pending_count()
954
+ )
955
+ metrics.update(partnership_metrics)
956
+
957
+ # Get decay metrics from manager
958
+ active_decays = self._decay_manager.get_active_decays()
959
+ decay_metrics = self._metrics_collector.collect_decay_metrics(len(active_decays), 0, len(active_decays))
960
+ metrics.update(decay_metrics)
961
+
962
+ # Operational metrics
963
+ operational_metrics = self._metrics_collector.collect_operational_metrics(
964
+ self._consent_checks,
965
+ self._consent_grants,
966
+ self._consent_revokes,
967
+ self._expired_cleanups,
968
+ self._tool_executions,
969
+ self._tool_failures,
970
+ )
971
+ metrics.update(operational_metrics)
972
+
973
+ # AIR metrics
974
+ air_metrics_dict = self._air_manager.get_metrics()
975
+ air_metrics = self._extract_air_metrics(air_metrics_dict)
976
+ metrics.update(air_metrics)
977
+
978
+ # Service health
979
+ metrics["consent_service_uptime_seconds"] = (
980
+ self._calculate_uptime() if hasattr(self, "_calculate_uptime") else 0.0
981
+ )
982
+
983
+ return metrics
984
+
985
+ def _check_dependencies(self) -> bool:
986
+ """Check service dependencies."""
987
+ return self._time_service is not None
988
+
989
+ def _get_actions(self) -> List[str]:
990
+ """Get available actions - not used for non-bussed services."""
991
+ return ["upgrade_relationship", "degrade_relationship"]
992
+
993
+ # ToolService Protocol Implementation
994
+
995
+ async def execute_tool(self, tool_name: str, parameters: JSONDict) -> ToolExecutionResult:
996
+ """Execute a tool and return the result."""
997
+ self._track_request() # Track the tool execution
998
+ self._tool_executions += 1
999
+
1000
+ if tool_name == "upgrade_relationship":
1001
+ result = await self._upgrade_relationship_tool(parameters)
1002
+ elif tool_name == "degrade_relationship":
1003
+ result = await self._degrade_relationship_tool(parameters)
1004
+ else:
1005
+ self._tool_failures += 1 # Unknown tool is a failure!
1006
+ return ToolExecutionResult(
1007
+ tool_name=tool_name,
1008
+ status=ToolExecutionStatus.NOT_FOUND,
1009
+ success=False,
1010
+ data=None,
1011
+ error=f"Unknown tool: {tool_name}",
1012
+ correlation_id=f"consent_{tool_name}_{self._now().timestamp()}",
1013
+ )
1014
+
1015
+ # Track failures
1016
+ if not result.get("success", False):
1017
+ self._tool_failures += 1
1018
+
1019
+ return ToolExecutionResult(
1020
+ tool_name=tool_name,
1021
+ status=ToolExecutionStatus.COMPLETED if result.get("success") else ToolExecutionStatus.FAILED,
1022
+ success=result.get("success", False),
1023
+ data=result,
1024
+ error=result.get("error"),
1025
+ correlation_id=f"consent_{tool_name}_{self._now().timestamp()}",
1026
+ )
1027
+
1028
+ async def get_available_tools(self) -> List[str]:
1029
+ """Get list of available tool names."""
1030
+ return ["upgrade_relationship", "degrade_relationship"]
1031
+
1032
+ async def list_tools(self) -> List[str]:
1033
+ """List available tools - required by ToolServiceProtocol."""
1034
+ return ["upgrade_relationship", "degrade_relationship"]
1035
+
1036
+ async def get_tool_schema(self, tool_name: str) -> Optional[ToolParameterSchema]:
1037
+ """Get parameter schema for a specific tool."""
1038
+ schemas = {
1039
+ "upgrade_relationship": ToolParameterSchema(
1040
+ type="object",
1041
+ properties={
1042
+ "user_id": {"type": "string", "description": "User ID requesting the upgrade"},
1043
+ "reason": {
1044
+ "type": "string",
1045
+ "description": "Reason for upgrade request",
1046
+ "default": "User requested partnership",
1047
+ },
1048
+ },
1049
+ required=["user_id"],
1050
+ ),
1051
+ "degrade_relationship": ToolParameterSchema(
1052
+ type="object",
1053
+ properties={
1054
+ "user_id": {"type": "string", "description": "User ID requesting the downgrade"},
1055
+ "target_stream": {
1056
+ "type": "string",
1057
+ "description": "Target stream: TEMPORARY or ANONYMOUS",
1058
+ "default": "TEMPORARY",
1059
+ },
1060
+ "reason": {
1061
+ "type": "string",
1062
+ "description": "Reason for downgrade",
1063
+ "default": "User requested downgrade",
1064
+ },
1065
+ },
1066
+ required=["user_id"],
1067
+ ),
1068
+ }
1069
+ return schemas.get(tool_name)
1070
+
1071
+ async def get_tool_info(self, tool_name: str) -> Optional[ToolInfo]:
1072
+ """Get detailed information about a specific tool."""
1073
+ tools_info = {
1074
+ "upgrade_relationship": ToolInfo(
1075
+ name="upgrade_relationship",
1076
+ description="Request to upgrade user relationship to PARTNERED (requires bilateral consent)",
1077
+ parameters=ToolParameterSchema(
1078
+ type="object",
1079
+ properties={
1080
+ "user_id": {"type": "string", "description": "User ID requesting the upgrade"},
1081
+ "reason": {
1082
+ "type": "string",
1083
+ "description": "Reason for upgrade request",
1084
+ "default": "User requested partnership",
1085
+ },
1086
+ },
1087
+ required=["user_id"],
1088
+ ),
1089
+ ),
1090
+ "degrade_relationship": ToolInfo(
1091
+ name="degrade_relationship",
1092
+ description="Request to downgrade user relationship to TEMPORARY or ANONYMOUS",
1093
+ parameters=ToolParameterSchema(
1094
+ type="object",
1095
+ properties={
1096
+ "user_id": {"type": "string", "description": "User ID requesting the downgrade"},
1097
+ "target_stream": {
1098
+ "type": "string",
1099
+ "description": "Target stream: TEMPORARY or ANONYMOUS",
1100
+ "default": "TEMPORARY",
1101
+ },
1102
+ "reason": {
1103
+ "type": "string",
1104
+ "description": "Reason for downgrade",
1105
+ "default": "User requested downgrade",
1106
+ },
1107
+ },
1108
+ required=["user_id"],
1109
+ ),
1110
+ ),
1111
+ }
1112
+ return tools_info.get(tool_name)
1113
+
1114
+ async def get_all_tool_info(self) -> List[ToolInfo]:
1115
+ """Get info for all available tools."""
1116
+ tools = []
1117
+ tool1 = await self.get_tool_info("upgrade_relationship")
1118
+ if tool1:
1119
+ tools.append(tool1)
1120
+ tool2 = await self.get_tool_info("degrade_relationship")
1121
+ if tool2:
1122
+ tools.append(tool2)
1123
+ return tools
1124
+
1125
+ async def get_tool_result(self, correlation_id: str, timeout: float = 30.0) -> Optional[ToolExecutionResult]:
1126
+ """Get result of an async tool execution by correlation ID."""
1127
+ # ConsentService tools are synchronous, so results are immediate
1128
+ return None
1129
+
1130
+ async def validate_parameters(self, tool_name: str, parameters: JSONDict) -> bool:
1131
+ """Validate parameters for a tool."""
1132
+ if tool_name == "upgrade_relationship":
1133
+ return "user_id" in parameters
1134
+ elif tool_name == "degrade_relationship":
1135
+ return "user_id" in parameters
1136
+ return False
1137
+
1138
+ async def _upgrade_relationship_tool(self, parameters: JSONDict) -> JSONDict:
1139
+ """Tool implementation for upgrading relationship to PARTNERED."""
1140
+ try:
1141
+ user_id = get_str(parameters, "user_id", "")
1142
+ reason = get_str(parameters, "reason", "User requested partnership")
1143
+
1144
+ if not user_id:
1145
+ return {"success": False, "error": "user_id is required"}
1146
+
1147
+ # Get current consent status
1148
+ try:
1149
+ current = await self.get_consent(user_id)
1150
+ except ConsentNotFoundError:
1151
+ # Create default TEMPORARY consent if none exists
1152
+ request = ConsentRequest(
1153
+ user_id=user_id,
1154
+ stream=ConsentStream.TEMPORARY,
1155
+ categories=[], # TEMPORARY doesn't need categories
1156
+ reason="Default consent for impact calculation",
1157
+ )
1158
+ current = await self.grant_consent(request)
1159
+
1160
+ if current.stream == ConsentStream.PARTNERED:
1161
+ return {
1162
+ "success": True,
1163
+ "message": "Already in PARTNERED relationship",
1164
+ "current_stream": "PARTNERED",
1165
+ "user_id": user_id,
1166
+ }
1167
+
1168
+ # Create upgrade request - this will need agent approval
1169
+ request = ConsentRequest(
1170
+ user_id=user_id,
1171
+ stream=ConsentStream.PARTNERED,
1172
+ categories=[ConsentCategory.INTERACTION, ConsentCategory.PREFERENCE],
1173
+ reason=reason,
1174
+ )
1175
+
1176
+ # Update to PARTNERED (pending agent approval via thought/task system)
1177
+ await self.update_consent(user_id, ConsentStream.PARTNERED, request.categories)
1178
+
1179
+ # Note: Partnership requests are now tracked by PartnershipManager
1180
+ return {
1181
+ "success": True,
1182
+ "message": "Partnership upgrade requested - requires agent approval",
1183
+ "current_stream": current.stream.value if hasattr(current.stream, "value") else current.stream,
1184
+ "requested_stream": "PARTNERED",
1185
+ "user_id": user_id,
1186
+ "status": "PENDING_APPROVAL",
1187
+ }
1188
+
1189
+ except Exception as e:
1190
+ logger.error(f"Failed to upgrade relationship: {e}")
1191
+ return {"success": False, "error": str(e)}
1192
+
1193
+ async def _degrade_relationship_tool(self, parameters: JSONDict) -> JSONDict:
1194
+ """Tool implementation for downgrading relationship."""
1195
+ try:
1196
+ user_id = get_str(parameters, "user_id", "")
1197
+ target_stream = get_str(parameters, "target_stream", "TEMPORARY")
1198
+ reason = get_str(parameters, "reason", "User requested downgrade")
1199
+
1200
+ if not user_id:
1201
+ return {"success": False, "error": "user_id is required"}
1202
+
1203
+ if target_stream not in ["TEMPORARY", "ANONYMOUS"]:
1204
+ return {"success": False, "error": "target_stream must be TEMPORARY or ANONYMOUS"}
1205
+
1206
+ # Convert uppercase to lowercase for enum
1207
+ target_stream_lower = target_stream.lower()
1208
+
1209
+ # Get current consent status
1210
+ try:
1211
+ current = await self.get_consent(user_id)
1212
+ except ConsentNotFoundError:
1213
+ # If no consent exists and target is ANONYMOUS, create it
1214
+ if target_stream == "ANONYMOUS":
1215
+ await self.update_consent(user_id, ConsentStream.ANONYMOUS, [ConsentCategory.RESEARCH])
1216
+ self._downgrades_completed += 1
1217
+ return {
1218
+ "success": True,
1219
+ "message": "Created ANONYMOUS consent for proactive opt-out",
1220
+ "current_stream": "ANONYMOUS",
1221
+ "user_id": user_id,
1222
+ }
1223
+ else:
1224
+ return {"success": False, "error": f"No consent found for user {user_id}"}
1225
+
1226
+ target = ConsentStream(target_stream_lower)
1227
+
1228
+ if current.stream == target:
1229
+ return {
1230
+ "success": True,
1231
+ "message": f"Already in {target_stream} relationship",
1232
+ "current_stream": target_stream,
1233
+ "user_id": user_id,
1234
+ }
1235
+
1236
+ # Downgrades are immediate - no approval needed
1237
+ if target == ConsentStream.TEMPORARY:
1238
+ categories = [ConsentCategory.INTERACTION]
1239
+ else: # ANONYMOUS
1240
+ categories = [ConsentCategory.RESEARCH]
1241
+
1242
+ await self.update_consent(user_id, target, categories)
1243
+
1244
+ self._downgrades_completed += 1
1245
+
1246
+ return {
1247
+ "success": True,
1248
+ "message": f"Relationship downgraded to {target_stream}",
1249
+ "previous_stream": current.stream.value if hasattr(current.stream, "value") else current.stream,
1250
+ "current_stream": target_stream,
1251
+ "user_id": user_id,
1252
+ }
1253
+
1254
+ except Exception as e:
1255
+ logger.error(f"Failed to degrade relationship: {e}")
1256
+ return {"success": False, "error": str(e)}