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,1547 @@
1
+ """SQL Tool Service for external data access - Refactored with dialects."""
2
+
3
+ import hashlib
4
+ import json
5
+ import logging
6
+ import os
7
+ import time
8
+ from pathlib import Path
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ from sqlalchemy import create_engine, text
12
+ from sqlalchemy.engine import Engine
13
+ from sqlalchemy.exc import SQLAlchemyError
14
+
15
+ from ciris_engine.logic.audit.signature_manager import AuditSignatureManager
16
+ from ciris_engine.logic.services.base_service import BaseService
17
+ from ciris_engine.protocols.services import TimeServiceProtocol, ToolService
18
+ from ciris_engine.schemas.adapters.tools import ToolExecutionResult, ToolExecutionStatus, ToolInfo, ToolParameterSchema
19
+ from ciris_engine.schemas.runtime.enums import ServiceType
20
+ from ciris_engine.schemas.types import JSONDict
21
+
22
+ from .dialects import BaseSQLDialect, get_dialect
23
+ from .privacy_schema_loader import PrivacySchemaLoader
24
+ from .schemas import (
25
+ DataLocation,
26
+ PrivacySchemaConfig,
27
+ SQLAnonymizationResult,
28
+ SQLConnectorConfig,
29
+ SQLDeletionResult,
30
+ SQLDialect,
31
+ SQLExportResult,
32
+ SQLQueryResult,
33
+ SQLStatsResult,
34
+ SQLVerificationResult,
35
+ )
36
+
37
+ logger = logging.getLogger(__name__)
38
+
39
+
40
+ class SQLToolService(BaseService, ToolService):
41
+ """Tool service for SQL database access and DSAR automation.
42
+
43
+ Provides dialect-aware SQL operations for SQLite, MySQL, and PostgreSQL.
44
+ Follows organic architecture: external data sources as tools.
45
+
46
+ Refactored features:
47
+ - Dialect separation for maintainability
48
+ - Hybrid YAML/graph privacy schema storage
49
+ - Cleaner service implementation
50
+ """
51
+
52
+ def __init__(
53
+ self,
54
+ config: Optional[SQLConnectorConfig] = None,
55
+ privacy_schema_path: Optional[str] = None,
56
+ *,
57
+ time_service: Optional[TimeServiceProtocol] = None,
58
+ **kwargs: Any, # Accept additional kwargs from service loader
59
+ ):
60
+ """Initialize SQL tool service.
61
+
62
+ Args:
63
+ config: Optional connector configuration
64
+ privacy_schema_path: Optional path to YAML/JSON privacy schema file
65
+ time_service: Time service for timestamps (injected by framework)
66
+ **kwargs: Additional keyword arguments (ignored, for framework compatibility)
67
+ """
68
+ super().__init__(time_service=time_service, service_name="SQLToolService")
69
+
70
+ # Load config from environment variable if not provided
71
+ if config is None:
72
+ config_path = os.environ.get("CIRIS_SQL_EXTERNAL_DATA_CONFIG")
73
+ if config_path:
74
+ config = self._load_config_from_file(config_path)
75
+ # Extract privacy schema path from config if provided
76
+ if config and hasattr(config, "privacy_schema_path"):
77
+ privacy_schema_path = config.privacy_schema_path
78
+
79
+ self._config = config
80
+ self._engine: Optional[Engine] = None
81
+ self._connector_id = config.connector_id if config else "sql"
82
+ self._dialect: Optional[BaseSQLDialect] = None
83
+ self._schema_loader = PrivacySchemaLoader()
84
+ self._privacy_schema_path = privacy_schema_path
85
+
86
+ # Signature manager for GDPR deletion verification (RSA-PSS signatures)
87
+ self._signature_manager: Optional[AuditSignatureManager] = None
88
+ self._signature_key_path = Path(os.environ.get("CIRIS_DATA_DIR", "data")) / "sql_deletion_keys"
89
+ self._signature_db_path = str(Path(os.environ.get("CIRIS_DATA_DIR", "data")) / "ciris.db")
90
+
91
+ # Result tracking and tool metadata
92
+ self._results: Dict[str, ToolExecutionResult] = {}
93
+ self._tool_schemas: Dict[str, ToolParameterSchema] = {}
94
+ self._tool_info: Dict[str, ToolInfo] = {}
95
+
96
+ # Build tool metadata after initialization
97
+ self._tool_schemas = self._build_tool_schemas()
98
+ self._tool_info = self._build_tool_info()
99
+
100
+ def _load_config_from_file(self, config_path: str) -> Optional[SQLConnectorConfig]:
101
+ """Load SQL connector configuration from JSON file.
102
+
103
+ Args:
104
+ config_path: Path to JSON configuration file
105
+
106
+ Returns:
107
+ SQLConnectorConfig if successful, None otherwise
108
+ """
109
+ try:
110
+ with open(config_path, "r") as f:
111
+ config_data = json.load(f)
112
+ return SQLConnectorConfig(**config_data)
113
+ except Exception as e:
114
+ # Can't use self.log_error here - base class not initialized yet
115
+ print(f"ERROR: Failed to load SQL config from {config_path}: {e}")
116
+ return None
117
+
118
+ async def initialize(self) -> None:
119
+ """Initialize the service and database connection."""
120
+ # Note: BaseService doesn't have initialize(), but this is required by framework
121
+ # await super().initialize() # Skip if not implemented
122
+
123
+ # TODO: Move to debug level after tool registration is confirmed working
124
+ self._logger.info(
125
+ f"SQLToolService initializing with config: {self._config.connector_id if self._config else 'None'}"
126
+ )
127
+ self._logger.info(f"SQLToolService has {len(self._tool_schemas)} tool schemas ready")
128
+ self._logger.info(f"SQLToolService has {len(self._tool_info)} tool info objects ready")
129
+
130
+ # Initialize signature manager for GDPR deletion verification
131
+ if self._time_service:
132
+ try:
133
+ self._signature_manager = AuditSignatureManager(
134
+ key_path=str(self._signature_key_path),
135
+ db_path=self._signature_db_path,
136
+ time_service=self._time_service,
137
+ )
138
+ self._signature_manager.initialize()
139
+ logger.info(f"Initialized deletion signature manager with key ID: {self._signature_manager.key_id}")
140
+ except Exception as e:
141
+ logger.warning(f"Failed to initialize signature manager: {e}. Signatures will not be available.")
142
+ self._signature_manager = None
143
+ else:
144
+ logger.warning("Time service not available - deletion verification signatures unavailable")
145
+ self._signature_manager = None
146
+
147
+ if self._config:
148
+ # Initialize dialect
149
+ self._dialect = get_dialect(self._config.dialect.value)
150
+
151
+ # Load privacy schema if path provided
152
+ if self._privacy_schema_path:
153
+ self._config.privacy_schema = self._schema_loader.load_from_file(self._privacy_schema_path)
154
+
155
+ # Connect to database
156
+ await self._connect()
157
+
158
+ # TODO: Move to debug level after tool registration is confirmed working
159
+ self._logger.info(f"SQLToolService initialized successfully - tools: {await self.list_tools()}")
160
+
161
+ async def _connect(self) -> None:
162
+ """Establish database connection."""
163
+ if not self._config:
164
+ return
165
+
166
+ try:
167
+ self._engine = create_engine(
168
+ self._config.connection_string,
169
+ connect_args={"timeout": self._config.connection_timeout},
170
+ pool_pre_ping=True,
171
+ echo=False,
172
+ )
173
+ # Test connection
174
+ with self._engine.connect() as conn:
175
+ conn.execute(text("SELECT 1"))
176
+ dialect_name = self._dialect.name if self._dialect else "unknown"
177
+ self._logger.info(f"Connected to {dialect_name} database: {self._connector_id}")
178
+ except SQLAlchemyError as e:
179
+ self._logger.error(f"Failed to connect to database: {e}")
180
+ raise
181
+
182
+ # BaseService Protocol Methods ----------------------------------------------
183
+ def get_service_type(self) -> ServiceType:
184
+ """Return service type."""
185
+ return ServiceType.TOOL
186
+
187
+ def _get_actions(self) -> List[str]:
188
+ """Return list of available actions/tools.
189
+
190
+ Uses generic SQL tool names. Connector ID is passed as parameter.
191
+ """
192
+ return [
193
+ "initialize_sql_connector",
194
+ "get_sql_service_metadata",
195
+ "sql_find_user_data",
196
+ "sql_export_user",
197
+ "sql_delete_user",
198
+ "sql_anonymize_user",
199
+ "sql_verify_deletion",
200
+ "sql_get_stats",
201
+ "sql_query",
202
+ ]
203
+
204
+ def _check_dependencies(self) -> bool:
205
+ """Check if service dependencies are met.
206
+
207
+ At start time, we just need config to be available.
208
+ Engine and dialect will be initialized in initialize().
209
+ """
210
+ return self._config is not None
211
+
212
+ # ToolServiceProtocol Methods -----------------------------------------------
213
+ async def list_tools(self) -> List[str]:
214
+ """List available SQL tools.
215
+
216
+ Returns generic SQL tool names. Connector ID is passed as parameter to each tool.
217
+
218
+ Returns:
219
+ List of generic SQL tool names
220
+ """
221
+ # TODO: Move to debug level after tool registration is confirmed working
222
+ self._logger.info(f"list_tools() called on SQLToolService")
223
+ tools = [
224
+ "initialize_sql_connector",
225
+ "get_sql_service_metadata",
226
+ "sql_find_user_data",
227
+ "sql_export_user",
228
+ "sql_delete_user",
229
+ "sql_anonymize_user",
230
+ "sql_verify_deletion",
231
+ "sql_get_stats",
232
+ "sql_query",
233
+ ]
234
+ # TODO: Move to debug level after tool registration is confirmed working
235
+ self._logger.info(f"list_tools() returning {len(tools)} tools: {tools}")
236
+ return tools
237
+
238
+ async def execute_tool(self, tool_name: str, parameters: JSONDict) -> ToolExecutionResult:
239
+ """Execute SQL tool.
240
+
241
+ Args:
242
+ tool_name: Generic SQL tool name (e.g. "sql_find_user_data")
243
+ parameters: Tool parameters including connector_id
244
+
245
+ Returns:
246
+ Tool execution result
247
+ """
248
+ # TODO: Move to debug level after tool registration is confirmed working
249
+ self._logger.info(f"execute_tool() called with tool_name={tool_name}, parameters={list(parameters.keys())}")
250
+
251
+ # Extract or generate correlation ID for result tracking
252
+ import uuid
253
+
254
+ correlation_id_raw = parameters.get("correlation_id")
255
+ correlation_id = str(correlation_id_raw) if correlation_id_raw else str(uuid.uuid4())
256
+
257
+ # Handle initialization and metadata tools (no connector_id validation needed)
258
+ if tool_name == "initialize_sql_connector":
259
+ result = await self._initialize_connector(parameters)
260
+ self._results[correlation_id] = result
261
+ return result
262
+ elif tool_name == "get_sql_service_metadata":
263
+ result = await self._get_sql_metadata(parameters)
264
+ self._results[correlation_id] = result
265
+ return result
266
+
267
+ # Validate tool name format for SQL tools
268
+ if not tool_name.startswith("sql_"):
269
+ result = ToolExecutionResult(
270
+ tool_name=tool_name,
271
+ status=ToolExecutionStatus.FAILED,
272
+ success=False,
273
+ data={},
274
+ error=f"Tool {tool_name} is not a SQL tool",
275
+ correlation_id=correlation_id,
276
+ )
277
+ self._results[correlation_id] = result
278
+ return result
279
+
280
+ # Extract connector_id from parameters
281
+ connector_id = parameters.get("connector_id")
282
+ if not connector_id:
283
+ result = ToolExecutionResult(
284
+ tool_name=tool_name,
285
+ status=ToolExecutionStatus.FAILED,
286
+ success=False,
287
+ data={},
288
+ error="connector_id parameter is required",
289
+ correlation_id=correlation_id,
290
+ )
291
+ self._results[correlation_id] = result
292
+ return result
293
+
294
+ # Verify this service handles the requested connector
295
+ if connector_id != self._connector_id:
296
+ result = ToolExecutionResult(
297
+ tool_name=tool_name,
298
+ status=ToolExecutionStatus.FAILED,
299
+ success=False,
300
+ data={},
301
+ error=f"This service handles connector '{self._connector_id}', not '{connector_id}'",
302
+ correlation_id=correlation_id,
303
+ )
304
+ self._results[correlation_id] = result
305
+ return result
306
+
307
+ # Extract method name from tool name
308
+ method_name = tool_name[4:] # Strip "sql_" prefix
309
+
310
+ # Route to appropriate method
311
+ exec_result: ToolExecutionResult
312
+ if method_name == "find_user_data":
313
+ exec_result = await self._find_user_data(parameters, correlation_id)
314
+ elif method_name == "export_user":
315
+ exec_result = await self._export_user(parameters, correlation_id)
316
+ elif method_name == "delete_user":
317
+ exec_result = await self._delete_user(parameters, correlation_id)
318
+ elif method_name == "anonymize_user":
319
+ exec_result = await self._anonymize_user(parameters, correlation_id)
320
+ elif method_name == "verify_deletion":
321
+ exec_result = await self._verify_deletion(parameters, correlation_id)
322
+ elif method_name == "get_stats":
323
+ exec_result = await self._get_stats(parameters, correlation_id)
324
+ elif method_name == "query":
325
+ exec_result = await self._query(parameters, correlation_id)
326
+ else:
327
+ exec_result = ToolExecutionResult(
328
+ tool_name=tool_name,
329
+ status=ToolExecutionStatus.FAILED,
330
+ success=False,
331
+ data={},
332
+ error=f"Unknown tool: {method_name}",
333
+ correlation_id=correlation_id,
334
+ )
335
+
336
+ # Store result for later retrieval
337
+ self._results[correlation_id] = exec_result
338
+ return exec_result
339
+
340
+ # Tool Implementation Methods -----------------------------------------------
341
+ async def _initialize_connector(self, parameters: JSONDict) -> ToolExecutionResult:
342
+ """Initialize or reconfigure SQL connector dynamically.
343
+
344
+ Args:
345
+ parameters: Dict containing:
346
+ - connector_id: Unique identifier for the connector
347
+ - connection_string: Database connection string
348
+ - dialect: SQL dialect (sqlite, postgres, mysql, etc.)
349
+ - privacy_schema_path: Path to privacy schema YAML file
350
+
351
+ Returns:
352
+ ToolExecutionResult with connector configuration details
353
+ """
354
+ # TODO: Move to debug level after tool registration is confirmed working
355
+ self._logger.info(f"_initialize_connector called with parameters: {list(parameters.keys())}")
356
+
357
+ # Extract or generate correlation ID
358
+ import uuid
359
+
360
+ correlation_id_raw = parameters.get("correlation_id")
361
+ correlation_id = str(correlation_id_raw) if correlation_id_raw else str(uuid.uuid4())
362
+
363
+ try:
364
+ # Extract required parameters
365
+ connector_id = parameters.get("connector_id")
366
+ connection_string = parameters.get("connection_string")
367
+ dialect = parameters.get("dialect")
368
+ privacy_schema_path = parameters.get("privacy_schema_path")
369
+
370
+ if not all([connector_id, connection_string, dialect]):
371
+ return ToolExecutionResult(
372
+ tool_name="initialize_sql_connector",
373
+ status=ToolExecutionStatus.FAILED,
374
+ success=False,
375
+ data={},
376
+ error="Missing required parameters: connector_id, connection_string, and dialect are required",
377
+ correlation_id=correlation_id,
378
+ )
379
+
380
+ # Parse dialect
381
+ try:
382
+ sql_dialect = SQLDialect(str(dialect))
383
+ except ValueError:
384
+ return ToolExecutionResult(
385
+ tool_name="initialize_sql_connector",
386
+ status=ToolExecutionStatus.FAILED,
387
+ success=False,
388
+ data={},
389
+ error=f"Invalid dialect: {dialect}. Must be one of: {[d.value for d in SQLDialect]}",
390
+ correlation_id=correlation_id,
391
+ )
392
+
393
+ # Load privacy schema if path provided
394
+ privacy_schema = None
395
+ if privacy_schema_path and isinstance(privacy_schema_path, str):
396
+ try:
397
+ with open(privacy_schema_path, "r") as f:
398
+ import yaml
399
+
400
+ schema_data = yaml.safe_load(f)
401
+ privacy_schema = PrivacySchemaConfig(**schema_data)
402
+ except Exception as e:
403
+ self._logger.error(f"Failed to load privacy schema from {privacy_schema_path}: {e}")
404
+ return ToolExecutionResult(
405
+ tool_name="initialize_sql_connector",
406
+ status=ToolExecutionStatus.FAILED,
407
+ success=False,
408
+ data={},
409
+ error=f"Failed to load privacy schema: {str(e)}",
410
+ correlation_id=correlation_id,
411
+ )
412
+
413
+ # Validate types for config creation
414
+ if not isinstance(connector_id, str):
415
+ connector_id = str(connector_id) if connector_id else ""
416
+ if not isinstance(connection_string, str):
417
+ connection_string = str(connection_string) if connection_string else ""
418
+
419
+ # Create new config with safe type conversions
420
+ conn_timeout = parameters.get("connection_timeout", 30)
421
+ q_timeout = parameters.get("query_timeout", 60)
422
+ retries = parameters.get("max_retries", 3)
423
+
424
+ new_config = SQLConnectorConfig(
425
+ connector_id=connector_id,
426
+ connection_string=connection_string,
427
+ dialect=sql_dialect,
428
+ privacy_schema=privacy_schema,
429
+ connection_timeout=int(conn_timeout) if isinstance(conn_timeout, (int, float, str)) else 30,
430
+ query_timeout=int(q_timeout) if isinstance(q_timeout, (int, float, str)) else 60,
431
+ max_retries=int(retries) if isinstance(retries, (int, float, str)) else 3,
432
+ )
433
+
434
+ # Update instance configuration
435
+ self._config = new_config
436
+ self._connector_id = connector_id
437
+ self._dialect = get_dialect(sql_dialect.value)
438
+
439
+ # Reinitialize engine
440
+ try:
441
+ from sqlalchemy import create_engine
442
+
443
+ self._engine = create_engine(connection_string, connect_args={"timeout": new_config.connection_timeout})
444
+
445
+ # Test connection
446
+ with self._engine.connect() as conn:
447
+ conn.execute(text("SELECT 1"))
448
+
449
+ except Exception as e:
450
+ self._logger.error(f"Failed to initialize database engine: {e}")
451
+ return ToolExecutionResult(
452
+ tool_name="initialize_sql_connector",
453
+ status=ToolExecutionStatus.FAILED,
454
+ success=False,
455
+ data={},
456
+ error=f"Failed to connect to database: {str(e)}",
457
+ correlation_id=correlation_id,
458
+ )
459
+
460
+ # Return success with configuration details
461
+ self._logger.info(f"Successfully initialized connector: {connector_id}")
462
+ return ToolExecutionResult(
463
+ tool_name="initialize_sql_connector",
464
+ status=ToolExecutionStatus.COMPLETED,
465
+ success=True,
466
+ data={
467
+ "connector_id": connector_id,
468
+ "dialect": str(dialect),
469
+ "privacy_schema_configured": privacy_schema is not None,
470
+ "connection_successful": True,
471
+ },
472
+ error=None,
473
+ correlation_id=correlation_id,
474
+ )
475
+
476
+ except Exception as e:
477
+ self._logger.error(f"Unexpected error in _initialize_connector: {e}")
478
+ return ToolExecutionResult(
479
+ tool_name="initialize_sql_connector",
480
+ status=ToolExecutionStatus.FAILED,
481
+ success=False,
482
+ data={},
483
+ error=f"Unexpected error: {str(e)}",
484
+ correlation_id=correlation_id,
485
+ )
486
+
487
+ async def _get_sql_metadata(self, parameters: JSONDict) -> ToolExecutionResult:
488
+ """Get metadata about the SQL connector and its capabilities.
489
+
490
+ Args:
491
+ parameters: Dict containing:
492
+ - connector_id: Connector to get metadata for
493
+
494
+ Returns:
495
+ ToolExecutionResult with connector metadata
496
+ """
497
+ # TODO: Move to debug level after tool registration is confirmed working
498
+ self._logger.info(f"_get_sql_metadata called with parameters: {list(parameters.keys())}")
499
+
500
+ # Extract or generate correlation ID
501
+ import uuid
502
+
503
+ correlation_id_raw = parameters.get("correlation_id")
504
+ correlation_id = str(correlation_id_raw) if correlation_id_raw else str(uuid.uuid4())
505
+
506
+ try:
507
+ connector_id = parameters.get("connector_id")
508
+
509
+ # Verify connector matches this service
510
+ if connector_id and connector_id != self._connector_id:
511
+ return ToolExecutionResult(
512
+ tool_name="get_sql_service_metadata",
513
+ status=ToolExecutionStatus.FAILED,
514
+ success=False,
515
+ data={},
516
+ error=f"This service handles connector '{self._connector_id}', not '{connector_id}'",
517
+ correlation_id=correlation_id,
518
+ )
519
+
520
+ if not self._config or not self._engine:
521
+ return ToolExecutionResult(
522
+ tool_name="get_sql_service_metadata",
523
+ status=ToolExecutionStatus.FAILED,
524
+ success=False,
525
+ data={},
526
+ error="Connector not initialized. Call initialize_sql_connector first.",
527
+ correlation_id=correlation_id,
528
+ )
529
+
530
+ # Get table count from database
531
+ table_count = 0
532
+ try:
533
+ from sqlalchemy import inspect
534
+
535
+ inspector = inspect(self._engine)
536
+ tables = inspector.get_table_names()
537
+ table_count = len(tables)
538
+ except Exception as e:
539
+ self._logger.warning(f"Could not get table count: {e}")
540
+
541
+ # Build metadata response
542
+ dialect_name = self._dialect.name if self._dialect else "unknown"
543
+ metadata = {
544
+ "data_source": True,
545
+ "data_source_type": "sql",
546
+ "contains_pii": True, # Assumed true if privacy schema configured
547
+ "gdpr_applicable": True, # Assumed true for SQL data sources
548
+ "connector_id": self._connector_id,
549
+ "dialect": dialect_name,
550
+ "dsar_capabilities": [
551
+ "find",
552
+ "export",
553
+ "delete",
554
+ "anonymize",
555
+ ],
556
+ "privacy_schema_configured": self._config.privacy_schema is not None,
557
+ "table_count": table_count,
558
+ }
559
+
560
+ self._logger.info(f"Successfully retrieved metadata for connector: {self._connector_id}")
561
+ return ToolExecutionResult(
562
+ tool_name="get_sql_service_metadata",
563
+ status=ToolExecutionStatus.COMPLETED,
564
+ success=True,
565
+ data=metadata,
566
+ error=None,
567
+ correlation_id=correlation_id,
568
+ )
569
+
570
+ except Exception as e:
571
+ self._logger.error(f"Unexpected error in _get_sql_metadata: {e}")
572
+ return ToolExecutionResult(
573
+ tool_name="get_sql_service_metadata",
574
+ status=ToolExecutionStatus.FAILED,
575
+ success=False,
576
+ data={},
577
+ error=f"Unexpected error: {str(e)}",
578
+ correlation_id=correlation_id,
579
+ )
580
+
581
+ async def _find_user_data(self, parameters: JSONDict, correlation_id: str) -> ToolExecutionResult:
582
+ """Find all locations where user data exists."""
583
+ if not self._engine or not self._config or not self._dialect:
584
+ return ToolExecutionResult(
585
+ tool_name="sql_find_user_data",
586
+ status=ToolExecutionStatus.FAILED,
587
+ success=False,
588
+ data={},
589
+ error="Database not configured",
590
+ correlation_id=correlation_id,
591
+ )
592
+
593
+ user_identifier = parameters.get("user_identifier")
594
+ if not user_identifier:
595
+ return ToolExecutionResult(
596
+ tool_name="sql_find_user_data",
597
+ status=ToolExecutionStatus.FAILED,
598
+ success=False,
599
+ data={},
600
+ error="user_identifier required",
601
+ correlation_id=correlation_id,
602
+ )
603
+
604
+ locations: List[DataLocation] = []
605
+
606
+ try:
607
+ # Check privacy_schema is not None before accessing tables
608
+ if self._config.privacy_schema is None:
609
+ return ToolExecutionResult(
610
+ tool_name="sql_find_user_data",
611
+ status=ToolExecutionStatus.FAILED,
612
+ success=False,
613
+ data={},
614
+ error="Privacy schema not configured",
615
+ correlation_id=correlation_id,
616
+ )
617
+
618
+ with self._engine.connect() as conn:
619
+ for table_mapping in self._config.privacy_schema.tables:
620
+ table_name = table_mapping.table_name
621
+ identifier_col = table_mapping.identifier_column
622
+
623
+ # Use dialect to build query
624
+ query_str = self._dialect.build_count_query(table_name, identifier_col)
625
+ result = conn.execute(text(query_str), {"user_id": user_identifier})
626
+ row_count = result.scalar()
627
+
628
+ if row_count and row_count > 0:
629
+ # Found data - record each privacy-sensitive column
630
+ for col_mapping in table_mapping.columns:
631
+ locations.append(
632
+ DataLocation(
633
+ table_name=table_name,
634
+ column_name=col_mapping.column_name,
635
+ data_type=col_mapping.data_type,
636
+ row_count=row_count,
637
+ )
638
+ )
639
+
640
+ return ToolExecutionResult(
641
+ tool_name="sql_find_user_data",
642
+ status=ToolExecutionStatus.COMPLETED,
643
+ success=True,
644
+ data={"locations": [loc.model_dump() for loc in locations]},
645
+ error=None,
646
+ correlation_id=correlation_id,
647
+ )
648
+ except SQLAlchemyError as e:
649
+ return ToolExecutionResult(
650
+ tool_name="sql_find_user_data",
651
+ status=ToolExecutionStatus.FAILED,
652
+ success=False,
653
+ data={},
654
+ error=f"Database error: {e}",
655
+ correlation_id=correlation_id,
656
+ )
657
+
658
+ async def _export_user(self, parameters: JSONDict, correlation_id: str) -> ToolExecutionResult:
659
+ """Export all user data."""
660
+ if not self._engine or not self._config or not self._dialect:
661
+ return ToolExecutionResult(
662
+ tool_name="sql_export_user",
663
+ status=ToolExecutionStatus.FAILED,
664
+ success=False,
665
+ data={},
666
+ error="Database not configured",
667
+ correlation_id=correlation_id,
668
+ )
669
+
670
+ user_identifier = parameters.get("user_identifier")
671
+ export_format = parameters.get("export_format", "json")
672
+
673
+ if not user_identifier:
674
+ return ToolExecutionResult(
675
+ tool_name="sql_export_user",
676
+ status=ToolExecutionStatus.FAILED,
677
+ success=False,
678
+ data={},
679
+ error="user_identifier required",
680
+ correlation_id=correlation_id,
681
+ )
682
+
683
+ data: Dict[str, List[Dict[str, Any]]] = {}
684
+ total_rows = 0
685
+
686
+ try:
687
+ # Check privacy_schema is not None before accessing tables
688
+ if self._config.privacy_schema is None:
689
+ return ToolExecutionResult(
690
+ tool_name="sql_export_user",
691
+ status=ToolExecutionStatus.FAILED,
692
+ success=False,
693
+ data={},
694
+ error="Privacy schema not configured",
695
+ correlation_id=correlation_id,
696
+ )
697
+
698
+ with self._engine.connect() as conn:
699
+ for table_mapping in self._config.privacy_schema.tables:
700
+ table_name = table_mapping.table_name
701
+ identifier_col = table_mapping.identifier_column
702
+
703
+ # Use dialect to build query
704
+ query_str = self._dialect.build_select_query(table_name, identifier_col)
705
+ result = conn.execute(text(query_str), {"user_id": user_identifier})
706
+
707
+ rows = []
708
+ for row in result:
709
+ rows.append(dict(row._mapping))
710
+
711
+ if rows:
712
+ data[table_name] = rows
713
+ total_rows += len(rows)
714
+
715
+ # Generate checksum
716
+ data_json = json.dumps(data, sort_keys=True)
717
+ checksum = hashlib.sha256(data_json.encode()).hexdigest()
718
+
719
+ export_result = SQLExportResult(
720
+ success=True,
721
+ user_identifier=str(user_identifier),
722
+ tables_exported=list(data.keys()),
723
+ total_rows=total_rows,
724
+ data=data,
725
+ export_format=str(export_format),
726
+ checksum=checksum,
727
+ )
728
+
729
+ return ToolExecutionResult(
730
+ tool_name="sql_export_user",
731
+ status=ToolExecutionStatus.COMPLETED,
732
+ success=True,
733
+ data=export_result.model_dump(),
734
+ error=None,
735
+ correlation_id=correlation_id,
736
+ )
737
+ except SQLAlchemyError as e:
738
+ return ToolExecutionResult(
739
+ tool_name="sql_export_user",
740
+ status=ToolExecutionStatus.FAILED,
741
+ success=False,
742
+ data={},
743
+ error=f"Database error: {e}",
744
+ correlation_id=correlation_id,
745
+ )
746
+
747
+ async def _delete_user(self, parameters: JSONDict, correlation_id: str) -> ToolExecutionResult:
748
+ """Delete all user data."""
749
+ if not self._engine or not self._config or not self._dialect:
750
+ return ToolExecutionResult(
751
+ tool_name="sql_delete_user",
752
+ status=ToolExecutionStatus.FAILED,
753
+ success=False,
754
+ data={},
755
+ error="Database not configured",
756
+ correlation_id=correlation_id,
757
+ )
758
+
759
+ user_identifier = parameters.get("user_identifier")
760
+ verify = parameters.get("verify", True)
761
+
762
+ if not user_identifier:
763
+ return ToolExecutionResult(
764
+ tool_name="sql_delete_user",
765
+ status=ToolExecutionStatus.FAILED,
766
+ success=False,
767
+ data={},
768
+ error="user_identifier required",
769
+ correlation_id=correlation_id,
770
+ )
771
+
772
+ tables_affected: List[str] = []
773
+ total_rows_deleted = 0
774
+ cascade_deletions: Dict[str, int] = {}
775
+
776
+ try:
777
+ # Check privacy_schema is not None before accessing tables
778
+ if self._config.privacy_schema is None:
779
+ return ToolExecutionResult(
780
+ tool_name="sql_delete_user",
781
+ status=ToolExecutionStatus.FAILED,
782
+ success=False,
783
+ data={},
784
+ error="Privacy schema not configured",
785
+ correlation_id=correlation_id,
786
+ )
787
+
788
+ with self._engine.begin() as conn: # Transaction
789
+ for table_mapping in self._config.privacy_schema.tables:
790
+ table_name = table_mapping.table_name
791
+ identifier_col = table_mapping.identifier_column
792
+
793
+ # Use dialect to build query
794
+ query_str = self._dialect.build_delete_query(table_name, identifier_col)
795
+ result = conn.execute(text(query_str), {"user_id": user_identifier})
796
+ rows_deleted = result.rowcount
797
+
798
+ if rows_deleted > 0:
799
+ tables_affected.append(table_name)
800
+ total_rows_deleted += rows_deleted
801
+
802
+ # Cascade deletions
803
+ for cascade_table in table_mapping.cascade_deletes:
804
+ cascade_query_str = self._dialect.build_delete_query(cascade_table, identifier_col)
805
+ cascade_result = conn.execute(text(cascade_query_str), {"user_id": user_identifier})
806
+ cascade_count = cascade_result.rowcount
807
+ if cascade_count > 0:
808
+ cascade_deletions[cascade_table] = cascade_count
809
+ total_rows_deleted += cascade_count
810
+
811
+ # Verify deletion if requested
812
+ verification_passed = False
813
+ if verify:
814
+ verify_result = await self._verify_deletion(
815
+ {"user_identifier": user_identifier, "sign": False}, correlation_id
816
+ )
817
+ if verify_result.data is not None and isinstance(verify_result.data, dict):
818
+ verification_passed = bool(verify_result.data.get("zero_data_confirmed", False))
819
+ else:
820
+ verification_passed = False
821
+
822
+ deletion_result = SQLDeletionResult(
823
+ success=True,
824
+ user_identifier=str(user_identifier),
825
+ tables_affected=tables_affected,
826
+ total_rows_deleted=total_rows_deleted,
827
+ cascade_deletions=cascade_deletions,
828
+ verification_passed=verification_passed,
829
+ )
830
+
831
+ return ToolExecutionResult(
832
+ tool_name="sql_delete_user",
833
+ status=ToolExecutionStatus.COMPLETED,
834
+ success=True,
835
+ data=deletion_result.model_dump(),
836
+ error=None,
837
+ correlation_id=correlation_id,
838
+ )
839
+ except SQLAlchemyError as e:
840
+ return ToolExecutionResult(
841
+ tool_name="sql_delete_user",
842
+ status=ToolExecutionStatus.FAILED,
843
+ success=False,
844
+ data={},
845
+ error=f"Database error: {e}",
846
+ correlation_id=correlation_id,
847
+ )
848
+
849
+ async def _anonymize_user(self, parameters: JSONDict, correlation_id: str) -> ToolExecutionResult:
850
+ """Anonymize user data instead of deleting."""
851
+ if not self._engine or not self._config or not self._dialect:
852
+ return ToolExecutionResult(
853
+ tool_name="sql_anonymize_user",
854
+ status=ToolExecutionStatus.FAILED,
855
+ success=False,
856
+ data={},
857
+ error="Database not configured",
858
+ correlation_id=correlation_id,
859
+ )
860
+
861
+ user_identifier = parameters.get("user_identifier")
862
+ strategy = parameters.get("strategy", "pseudonymize")
863
+
864
+ if not user_identifier:
865
+ return ToolExecutionResult(
866
+ tool_name="sql_anonymize_user",
867
+ status=ToolExecutionStatus.FAILED,
868
+ success=False,
869
+ data={},
870
+ error="user_identifier required",
871
+ correlation_id=correlation_id,
872
+ )
873
+
874
+ tables_affected: List[str] = []
875
+ columns_anonymized: Dict[str, List[str]] = {}
876
+ total_rows_affected = 0
877
+
878
+ try:
879
+ # Check privacy_schema is not None before accessing tables
880
+ if self._config.privacy_schema is None:
881
+ return ToolExecutionResult(
882
+ tool_name="sql_anonymize_user",
883
+ status=ToolExecutionStatus.FAILED,
884
+ success=False,
885
+ data={},
886
+ error="Privacy schema not configured",
887
+ correlation_id=correlation_id,
888
+ )
889
+
890
+ with self._engine.begin() as conn: # Transaction
891
+ for table_mapping in self._config.privacy_schema.tables:
892
+ table_name = table_mapping.table_name
893
+ identifier_col = table_mapping.identifier_column
894
+ cols_to_anonymize = []
895
+
896
+ # Use dialect to build anonymization query
897
+ column_mappings = [cm for cm in table_mapping.columns if cm.anonymization_strategy != "delete"]
898
+
899
+ if column_mappings:
900
+ query_str = self._dialect.build_update_query(
901
+ table_name,
902
+ identifier_col,
903
+ column_mappings,
904
+ str(user_identifier),
905
+ )
906
+
907
+ if query_str:
908
+ result = conn.execute(text(query_str), {"user_id": user_identifier})
909
+ rows_affected = result.rowcount
910
+
911
+ if rows_affected > 0:
912
+ tables_affected.append(table_name)
913
+ cols_to_anonymize = [cm.column_name for cm in column_mappings]
914
+ columns_anonymized[table_name] = cols_to_anonymize
915
+ total_rows_affected += rows_affected
916
+
917
+ anonymization_result = SQLAnonymizationResult(
918
+ success=True,
919
+ user_identifier=str(user_identifier),
920
+ tables_affected=tables_affected,
921
+ columns_anonymized=columns_anonymized,
922
+ total_rows_affected=total_rows_affected,
923
+ anonymization_strategy=str(strategy),
924
+ )
925
+
926
+ return ToolExecutionResult(
927
+ tool_name="sql_anonymize_user",
928
+ status=ToolExecutionStatus.COMPLETED,
929
+ success=True,
930
+ data=anonymization_result.model_dump(),
931
+ error=None,
932
+ correlation_id=correlation_id,
933
+ )
934
+ except SQLAlchemyError as e:
935
+ return ToolExecutionResult(
936
+ tool_name="sql_anonymize_user",
937
+ status=ToolExecutionStatus.FAILED,
938
+ success=False,
939
+ data={},
940
+ error=f"Database error: {e}",
941
+ correlation_id=correlation_id,
942
+ )
943
+
944
+ async def _verify_deletion(self, parameters: JSONDict, correlation_id: str) -> ToolExecutionResult:
945
+ """Verify that user data has been completely deleted."""
946
+ if not self._engine or not self._config or not self._dialect:
947
+ return ToolExecutionResult(
948
+ tool_name="sql_verify_deletion",
949
+ status=ToolExecutionStatus.FAILED,
950
+ success=False,
951
+ data={},
952
+ error="Database not configured",
953
+ correlation_id=correlation_id,
954
+ )
955
+
956
+ user_identifier = parameters.get("user_identifier")
957
+ sign = parameters.get("sign", True)
958
+
959
+ if not user_identifier:
960
+ return ToolExecutionResult(
961
+ tool_name="sql_verify_deletion",
962
+ status=ToolExecutionStatus.FAILED,
963
+ success=False,
964
+ data={},
965
+ error="user_identifier required",
966
+ correlation_id=correlation_id,
967
+ )
968
+
969
+ tables_scanned: List[str] = []
970
+ remaining_data: Dict[str, int] = {}
971
+
972
+ try:
973
+ # Check privacy_schema is not None before accessing tables
974
+ if self._config.privacy_schema is None:
975
+ return ToolExecutionResult(
976
+ tool_name="sql_verify_deletion",
977
+ status=ToolExecutionStatus.FAILED,
978
+ success=False,
979
+ data={},
980
+ error="Privacy schema not configured",
981
+ correlation_id=correlation_id,
982
+ )
983
+
984
+ with self._engine.connect() as conn:
985
+ for table_mapping in self._config.privacy_schema.tables:
986
+ table_name = table_mapping.table_name
987
+ identifier_col = table_mapping.identifier_column
988
+
989
+ # Use dialect to build query
990
+ query_str = self._dialect.build_count_query(table_name, identifier_col)
991
+ result = conn.execute(text(query_str), {"user_id": user_identifier})
992
+ row_count = result.scalar()
993
+
994
+ tables_scanned.append(table_name)
995
+ if row_count and row_count > 0:
996
+ remaining_data[table_name] = row_count
997
+
998
+ zero_data_confirmed = len(remaining_data) == 0
999
+
1000
+ # Check if time_service is available
1001
+ if self._time_service is None:
1002
+ # Fallback timestamp using datetime
1003
+ from datetime import datetime
1004
+
1005
+ timestamp = datetime.utcnow().isoformat() + "Z"
1006
+ else:
1007
+ # Try to get timestamp from time service
1008
+ # TimeServiceProtocol doesn't have get_utc_timestamp_str, use alternative
1009
+ from datetime import datetime
1010
+
1011
+ timestamp = datetime.utcnow().isoformat() + "Z"
1012
+
1013
+ # Generate RSA-PSS signature for GDPR Article 17 deletion verification
1014
+ cryptographic_proof = None
1015
+ if sign and zero_data_confirmed:
1016
+ if self._signature_manager:
1017
+ try:
1018
+ # Create deterministic hash of verification data
1019
+ verification_data = (
1020
+ f"{user_identifier}|{timestamp}|{zero_data_confirmed}|{','.join(sorted(tables_scanned))}"
1021
+ )
1022
+ data_hash = hashlib.sha256(verification_data.encode("utf-8")).hexdigest()
1023
+
1024
+ # Sign the hash using RSA-PSS
1025
+ signature = self._signature_manager.sign_entry(data_hash)
1026
+ key_id = self._signature_manager.key_id or "unknown"
1027
+ cryptographic_proof = f"rsa-pss:{key_id}:{signature}"
1028
+
1029
+ logger.info(
1030
+ f"Generated deletion verification signature for {user_identifier} "
1031
+ f"(key: {key_id[:8]}...)"
1032
+ )
1033
+ except Exception as e:
1034
+ logger.error(f"Failed to generate deletion verification signature: {e}")
1035
+ cryptographic_proof = None
1036
+ else:
1037
+ logger.warning("Signature manager not available - deletion verification signature unavailable")
1038
+
1039
+ verification_result = SQLVerificationResult(
1040
+ success=True,
1041
+ user_identifier=str(user_identifier),
1042
+ zero_data_confirmed=zero_data_confirmed,
1043
+ tables_scanned=tables_scanned,
1044
+ remaining_data=remaining_data,
1045
+ verification_timestamp=timestamp,
1046
+ cryptographic_proof=cryptographic_proof,
1047
+ )
1048
+
1049
+ return ToolExecutionResult(
1050
+ tool_name="sql_verify_deletion",
1051
+ status=ToolExecutionStatus.COMPLETED,
1052
+ success=True,
1053
+ data=verification_result.model_dump(),
1054
+ error=None,
1055
+ correlation_id=correlation_id,
1056
+ )
1057
+ except SQLAlchemyError as e:
1058
+ return ToolExecutionResult(
1059
+ tool_name="sql_verify_deletion",
1060
+ status=ToolExecutionStatus.FAILED,
1061
+ success=False,
1062
+ data={},
1063
+ error=f"Database error: {e}",
1064
+ correlation_id=correlation_id,
1065
+ )
1066
+
1067
+ async def _get_stats(self, parameters: JSONDict, correlation_id: str) -> ToolExecutionResult:
1068
+ """Get database statistics."""
1069
+ if not self._engine or not self._config or not self._dialect:
1070
+ return ToolExecutionResult(
1071
+ tool_name="sql_get_stats",
1072
+ status=ToolExecutionStatus.FAILED,
1073
+ success=False,
1074
+ data={},
1075
+ error="Database not configured",
1076
+ correlation_id=correlation_id,
1077
+ )
1078
+
1079
+ tables: Dict[str, int] = {}
1080
+ total_rows = 0
1081
+
1082
+ try:
1083
+ # Check privacy_schema is not None before accessing tables
1084
+ if self._config.privacy_schema is None:
1085
+ return ToolExecutionResult(
1086
+ tool_name="sql_get_stats",
1087
+ status=ToolExecutionStatus.FAILED,
1088
+ success=False,
1089
+ data={},
1090
+ error="Privacy schema not configured",
1091
+ correlation_id=correlation_id,
1092
+ )
1093
+
1094
+ with self._engine.connect() as conn:
1095
+ # Get row counts for all privacy tables
1096
+ for table_mapping in self._config.privacy_schema.tables:
1097
+ table_name = table_mapping.table_name
1098
+ query_str = f"SELECT COUNT(*) as cnt FROM {table_name}"
1099
+ result = conn.execute(text(query_str))
1100
+ row_count = result.scalar()
1101
+
1102
+ tables[table_name] = row_count or 0
1103
+ total_rows += row_count or 0
1104
+
1105
+ # Get database size if supported
1106
+ database_size_mb = None
1107
+ size_query = self._dialect.get_database_size_query()
1108
+ if size_query:
1109
+ result = conn.execute(text(size_query))
1110
+ database_size_mb = result.scalar()
1111
+
1112
+ stats_result = SQLStatsResult(
1113
+ success=True,
1114
+ total_tables=len(tables),
1115
+ total_rows=total_rows,
1116
+ tables=tables,
1117
+ database_size_mb=database_size_mb,
1118
+ )
1119
+
1120
+ return ToolExecutionResult(
1121
+ tool_name="sql_get_stats",
1122
+ status=ToolExecutionStatus.COMPLETED,
1123
+ success=True,
1124
+ data=stats_result.model_dump(),
1125
+ error=None,
1126
+ correlation_id=correlation_id,
1127
+ )
1128
+ except SQLAlchemyError as e:
1129
+ return ToolExecutionResult(
1130
+ tool_name="sql_get_stats",
1131
+ status=ToolExecutionStatus.FAILED,
1132
+ success=False,
1133
+ data={},
1134
+ error=f"Database error: {e}",
1135
+ correlation_id=correlation_id,
1136
+ )
1137
+
1138
+ def _validate_sql_query(self, sql: str) -> Optional[str]:
1139
+ """Validate SQL query against privacy schema.
1140
+
1141
+ Security constraints:
1142
+ 1. Only SELECT statements allowed
1143
+ 2. Must query configured tables only
1144
+ 3. No DDL (CREATE, DROP, ALTER)
1145
+ 4. No DML (INSERT, UPDATE, DELETE) except via dedicated tools
1146
+
1147
+ Args:
1148
+ sql: SQL query string to validate
1149
+
1150
+ Returns:
1151
+ Error message if invalid, None if valid
1152
+ """
1153
+ # Normalize query for validation
1154
+ sql_upper = sql.strip().upper()
1155
+
1156
+ # Only allow SELECT queries
1157
+ if not sql_upper.startswith("SELECT"):
1158
+ return "Only SELECT queries are allowed. Use dedicated tools for modifications."
1159
+
1160
+ # Block dangerous keywords
1161
+ dangerous_keywords = [
1162
+ "DROP",
1163
+ "CREATE",
1164
+ "ALTER",
1165
+ "TRUNCATE",
1166
+ "INSERT",
1167
+ "UPDATE",
1168
+ "DELETE",
1169
+ "GRANT",
1170
+ "REVOKE",
1171
+ "EXEC",
1172
+ "EXECUTE",
1173
+ ]
1174
+ for keyword in dangerous_keywords:
1175
+ if keyword in sql_upper:
1176
+ return f"Keyword '{keyword}' is not allowed in queries"
1177
+
1178
+ # Validate against privacy schema if configured
1179
+ if self._config and self._config.privacy_schema:
1180
+ # Extract table names from privacy schema
1181
+ allowed_tables = [table.table_name.upper() for table in self._config.privacy_schema.tables]
1182
+
1183
+ # Basic table name extraction (this is not perfect, but provides basic protection)
1184
+ # Look for FROM and JOIN clauses
1185
+ import re
1186
+
1187
+ # Find FROM clause
1188
+ from_match = re.search(r"\bFROM\s+(\w+)", sql_upper)
1189
+ if from_match:
1190
+ table_name = from_match.group(1)
1191
+ if table_name not in allowed_tables:
1192
+ return f"Table '{table_name}' is not in privacy schema. Allowed: {', '.join(allowed_tables)}"
1193
+
1194
+ # Find JOIN clauses
1195
+ join_matches = re.findall(r"\bJOIN\s+(\w+)", sql_upper)
1196
+ for table_name in join_matches:
1197
+ if table_name not in allowed_tables:
1198
+ return f"Table '{table_name}' is not in privacy schema. Allowed: {', '.join(allowed_tables)}"
1199
+
1200
+ return None # Valid query
1201
+
1202
+ async def _query(self, parameters: JSONDict, correlation_id: str) -> ToolExecutionResult:
1203
+ """Execute raw SQL query (with privacy constraints)."""
1204
+ if not self._engine:
1205
+ return ToolExecutionResult(
1206
+ tool_name="sql_query",
1207
+ status=ToolExecutionStatus.FAILED,
1208
+ success=False,
1209
+ data={},
1210
+ error="Database not configured",
1211
+ correlation_id=correlation_id,
1212
+ )
1213
+
1214
+ sql = parameters.get("sql")
1215
+ query_params = parameters.get("parameters", {})
1216
+
1217
+ if not sql:
1218
+ return ToolExecutionResult(
1219
+ tool_name="sql_query",
1220
+ status=ToolExecutionStatus.FAILED,
1221
+ success=False,
1222
+ data={},
1223
+ error="sql required",
1224
+ correlation_id=correlation_id,
1225
+ )
1226
+
1227
+ # Validate types
1228
+ if not isinstance(sql, str):
1229
+ return ToolExecutionResult(
1230
+ tool_name="sql_query",
1231
+ status=ToolExecutionStatus.FAILED,
1232
+ success=False,
1233
+ data={},
1234
+ error="sql parameter must be a string",
1235
+ correlation_id=correlation_id,
1236
+ )
1237
+
1238
+ if query_params is not None and not isinstance(query_params, dict):
1239
+ query_params = {}
1240
+
1241
+ # SECURITY: Validate SQL query against privacy schema
1242
+ # Only allow SELECT queries on configured tables
1243
+ validation_error = self._validate_sql_query(sql)
1244
+ if validation_error:
1245
+ return ToolExecutionResult(
1246
+ tool_name="sql_query",
1247
+ status=ToolExecutionStatus.FAILED,
1248
+ success=False,
1249
+ data={},
1250
+ error=f"SQL validation failed: {validation_error}",
1251
+ correlation_id=correlation_id,
1252
+ )
1253
+
1254
+ start_time = time.time()
1255
+
1256
+ try:
1257
+ with self._engine.connect() as conn:
1258
+ result = conn.execute(text(sql), query_params)
1259
+
1260
+ rows = []
1261
+ columns = []
1262
+ if result.returns_rows:
1263
+ columns = list(result.keys())
1264
+ for row in result:
1265
+ rows.append(dict(row._mapping))
1266
+
1267
+ execution_time_ms = (time.time() - start_time) * 1000
1268
+
1269
+ query_result = SQLQueryResult(
1270
+ success=True,
1271
+ row_count=len(rows),
1272
+ columns=columns,
1273
+ rows=rows,
1274
+ execution_time_ms=execution_time_ms,
1275
+ )
1276
+
1277
+ return ToolExecutionResult(
1278
+ tool_name="sql_query",
1279
+ status=ToolExecutionStatus.COMPLETED,
1280
+ success=True,
1281
+ data=query_result.model_dump(),
1282
+ error=None,
1283
+ correlation_id=correlation_id,
1284
+ )
1285
+ except SQLAlchemyError as e:
1286
+ return ToolExecutionResult(
1287
+ tool_name="sql_query",
1288
+ status=ToolExecutionStatus.FAILED,
1289
+ success=False,
1290
+ data={},
1291
+ error=f"Database error: {e}",
1292
+ correlation_id=correlation_id,
1293
+ )
1294
+
1295
+ # Tool Schema and Info Builders ---------------------------------------------
1296
+ def _build_tool_schemas(self) -> Dict[str, ToolParameterSchema]:
1297
+ """Build parameter schemas for all SQL tools.
1298
+
1299
+ Uses generic SQL tool names with connector_id as a parameter.
1300
+ """
1301
+ # Base properties that all SQL tools need
1302
+ base_props = {
1303
+ "connector_id": {"type": "string", "description": "SQL connector ID to use"},
1304
+ }
1305
+
1306
+ return {
1307
+ "initialize_sql_connector": ToolParameterSchema(
1308
+ type="object",
1309
+ properties={
1310
+ "connector_id": {"type": "string", "description": "Unique identifier for the connector"},
1311
+ "connection_string": {
1312
+ "type": "string",
1313
+ "description": "Database connection string (e.g., sqlite:///path/to/db.db)",
1314
+ },
1315
+ "dialect": {"type": "string", "description": "SQL dialect: sqlite, postgres, mysql, mssql"},
1316
+ "privacy_schema_path": {"type": "string", "description": "Path to privacy schema YAML file"},
1317
+ "connection_timeout": {
1318
+ "type": "integer",
1319
+ "description": "Connection timeout in seconds (default: 30)",
1320
+ },
1321
+ "query_timeout": {"type": "integer", "description": "Query timeout in seconds (default: 60)"},
1322
+ "max_retries": {"type": "integer", "description": "Maximum retry attempts (default: 3)"},
1323
+ },
1324
+ required=["connector_id", "connection_string", "dialect"],
1325
+ ),
1326
+ "get_sql_service_metadata": ToolParameterSchema(
1327
+ type="object",
1328
+ properties={
1329
+ "connector_id": {"type": "string", "description": "Connector to get metadata for"},
1330
+ },
1331
+ required=["connector_id"],
1332
+ ),
1333
+ "sql_find_user_data": ToolParameterSchema(
1334
+ type="object",
1335
+ properties={
1336
+ **base_props,
1337
+ "user_identifier": {"type": "string", "description": "User identifier (email, user_id, etc.)"},
1338
+ "identifier_type": {
1339
+ "type": "string",
1340
+ "description": "Type of identifier: email, user_id, phone, etc.",
1341
+ },
1342
+ },
1343
+ required=["connector_id", "user_identifier", "identifier_type"],
1344
+ ),
1345
+ "sql_export_user": ToolParameterSchema(
1346
+ type="object",
1347
+ properties={
1348
+ **base_props,
1349
+ "user_identifier": {"type": "string", "description": "User identifier"},
1350
+ "identifier_type": {"type": "string", "description": "Type of identifier"},
1351
+ "export_format": {"type": "string", "description": "Export format: json or csv (default: json)"},
1352
+ },
1353
+ required=["connector_id", "user_identifier", "identifier_type"],
1354
+ ),
1355
+ "sql_delete_user": ToolParameterSchema(
1356
+ type="object",
1357
+ properties={
1358
+ **base_props,
1359
+ "user_identifier": {"type": "string", "description": "User identifier"},
1360
+ "identifier_type": {"type": "string", "description": "Type of identifier"},
1361
+ "soft_delete": {"type": "boolean", "description": "Use soft delete if available (default: false)"},
1362
+ },
1363
+ required=["connector_id", "user_identifier", "identifier_type"],
1364
+ ),
1365
+ "sql_anonymize_user": ToolParameterSchema(
1366
+ type="object",
1367
+ properties={
1368
+ **base_props,
1369
+ "user_identifier": {"type": "string", "description": "User identifier"},
1370
+ "identifier_type": {"type": "string", "description": "Type of identifier"},
1371
+ },
1372
+ required=["connector_id", "user_identifier", "identifier_type"],
1373
+ ),
1374
+ "sql_verify_deletion": ToolParameterSchema(
1375
+ type="object",
1376
+ properties={
1377
+ **base_props,
1378
+ "user_identifier": {"type": "string", "description": "User identifier"},
1379
+ "identifier_type": {"type": "string", "description": "Type of identifier"},
1380
+ },
1381
+ required=["connector_id", "user_identifier", "identifier_type"],
1382
+ ),
1383
+ "sql_get_stats": ToolParameterSchema(
1384
+ type="object",
1385
+ properties={**base_props},
1386
+ required=["connector_id"],
1387
+ ),
1388
+ "sql_query": ToolParameterSchema(
1389
+ type="object",
1390
+ properties={
1391
+ **base_props,
1392
+ "query": {"type": "string", "description": "SQL query to execute (SELECT only)"},
1393
+ "parameters": {"type": "object", "description": "Query parameters for parameterized queries"},
1394
+ },
1395
+ required=["connector_id", "query"],
1396
+ ),
1397
+ }
1398
+
1399
+ def _build_tool_info(self) -> Dict[str, ToolInfo]:
1400
+ """Build ToolInfo objects for all SQL tools.
1401
+
1402
+ Uses generic SQL tool names. Connector ID is specified via parameter.
1403
+ """
1404
+ return {
1405
+ "initialize_sql_connector": ToolInfo(
1406
+ name="initialize_sql_connector",
1407
+ description="Initialize or reconfigure SQL connector with connection details and privacy schema",
1408
+ parameters=self._tool_schemas["initialize_sql_connector"],
1409
+ category="configuration",
1410
+ ),
1411
+ "get_sql_service_metadata": ToolInfo(
1412
+ name="get_sql_service_metadata",
1413
+ description="Get metadata about SQL connector including DSAR capabilities and table information",
1414
+ parameters=self._tool_schemas["get_sql_service_metadata"],
1415
+ category="metadata",
1416
+ ),
1417
+ "sql_find_user_data": ToolInfo(
1418
+ name="sql_find_user_data",
1419
+ description="Find all user data across configured SQL tables using privacy schema",
1420
+ parameters=self._tool_schemas["sql_find_user_data"],
1421
+ category="data_privacy",
1422
+ ),
1423
+ "sql_export_user": ToolInfo(
1424
+ name="sql_export_user",
1425
+ description="Export all user data in specified format (JSON or CSV)",
1426
+ parameters=self._tool_schemas["sql_export_user"],
1427
+ category="data_privacy",
1428
+ ),
1429
+ "sql_delete_user": ToolInfo(
1430
+ name="sql_delete_user",
1431
+ description="Delete all user data from configured SQL tables",
1432
+ parameters=self._tool_schemas["sql_delete_user"],
1433
+ category="data_privacy",
1434
+ ),
1435
+ "sql_anonymize_user": ToolInfo(
1436
+ name="sql_anonymize_user",
1437
+ description="Anonymize user PII using configured anonymization strategies",
1438
+ parameters=self._tool_schemas["sql_anonymize_user"],
1439
+ category="data_privacy",
1440
+ ),
1441
+ "sql_verify_deletion": ToolInfo(
1442
+ name="sql_verify_deletion",
1443
+ description="Verify that user data has been completely deleted",
1444
+ parameters=self._tool_schemas["sql_verify_deletion"],
1445
+ category="data_privacy",
1446
+ ),
1447
+ "sql_get_stats": ToolInfo(
1448
+ name="sql_get_stats",
1449
+ description="Get database statistics and table information",
1450
+ parameters=self._tool_schemas["sql_get_stats"],
1451
+ category="database",
1452
+ ),
1453
+ "sql_query": ToolInfo(
1454
+ name="sql_query",
1455
+ description="Execute a read-only SQL query (SELECT statements only)",
1456
+ parameters=self._tool_schemas["sql_query"],
1457
+ category="database",
1458
+ ),
1459
+ }
1460
+
1461
+ # Additional ToolServiceProtocol Methods ------------------------------------
1462
+ async def get_tool_schema(self, tool_name: str) -> Optional[ToolParameterSchema]:
1463
+ """Get parameter schema for a specific tool."""
1464
+ return self._tool_schemas.get(tool_name)
1465
+
1466
+ async def get_available_tools(self) -> List[str]:
1467
+ """Get list of all available tools (alias for list_tools)."""
1468
+ return await self.list_tools()
1469
+
1470
+ async def get_tool_info(self, tool_name: str) -> Optional[ToolInfo]:
1471
+ """Get detailed information about a specific tool."""
1472
+ return self._tool_info.get(tool_name)
1473
+
1474
+ async def get_all_tool_info(self) -> List[ToolInfo]:
1475
+ """Get detailed information about all available tools."""
1476
+ return list(self._tool_info.values())
1477
+
1478
+ async def validate_parameters(self, tool_name: str, parameters: JSONDict) -> bool:
1479
+ """Validate parameters for a specific tool without executing it."""
1480
+ schema = await self.get_tool_schema(tool_name)
1481
+ if not schema:
1482
+ return False
1483
+
1484
+ # Check required parameters
1485
+ for required_param in schema.required:
1486
+ if required_param not in parameters:
1487
+ return False
1488
+
1489
+ # Basic type validation could be added here
1490
+ return True
1491
+
1492
+ async def get_tool_result(self, correlation_id: str, timeout: float = 30.0) -> Optional[ToolExecutionResult]:
1493
+ """Get the result of a previously executed tool by correlation ID."""
1494
+ return self._results.get(correlation_id)
1495
+
1496
+ def get_service_metadata(self) -> Dict[str, Any]:
1497
+ """Return SQL data source metadata for DSAR coordination.
1498
+
1499
+ Returns:
1500
+ Dict with data source metadata including:
1501
+ - data_source: True (this is a data source)
1502
+ - data_source_type: "sql"
1503
+ - contains_pii: True (configured via privacy schema)
1504
+ - gdpr_applicable: True
1505
+ - connector_id: Unique connector identifier
1506
+ - dialect: SQL dialect (sqlite, postgresql, mysql)
1507
+ - dsar_capabilities: List of DSAR operations supported
1508
+ - privacy_schema_configured: Whether privacy schema is loaded
1509
+ - table_count: Number of tables configured for privacy
1510
+ """
1511
+ # Determine DSAR capabilities
1512
+ dsar_capabilities = []
1513
+ if self._config and self._config.privacy_schema:
1514
+ dsar_capabilities.extend(
1515
+ [
1516
+ "find_user_data",
1517
+ "export_user",
1518
+ "delete_user",
1519
+ "anonymize_user",
1520
+ "verify_deletion",
1521
+ ]
1522
+ )
1523
+
1524
+ # Count configured privacy tables
1525
+ table_count = 0
1526
+ if self._config and self._config.privacy_schema:
1527
+ table_count = len(self._config.privacy_schema.tables)
1528
+
1529
+ return {
1530
+ "data_source": True,
1531
+ "data_source_type": "sql",
1532
+ "contains_pii": True, # SQL databases configured with privacy schema contain PII
1533
+ "gdpr_applicable": True,
1534
+ "connector_id": self._connector_id,
1535
+ "dialect": self._dialect.name if self._dialect else None,
1536
+ "dsar_capabilities": dsar_capabilities,
1537
+ "privacy_schema_configured": self._config is not None and self._config.privacy_schema is not None,
1538
+ "table_count": table_count,
1539
+ }
1540
+
1541
+ async def shutdown(self) -> None:
1542
+ """Shutdown service and close database connection."""
1543
+ if self._engine:
1544
+ self._engine.dispose()
1545
+ self._logger.info("Database connection closed")
1546
+ # Note: BaseService doesn't have shutdown(), but this is required by framework
1547
+ # await super().shutdown() # Skip if not implemented