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.
- ciris_adapters/README.md +113 -0
- ciris_adapters/__init__.py +30 -0
- ciris_adapters/ciris_covenant_metrics/README.md +144 -0
- ciris_adapters/ciris_covenant_metrics/__init__.py +36 -0
- ciris_adapters/ciris_covenant_metrics/adapter.py +249 -0
- ciris_adapters/ciris_covenant_metrics/manifest.json +152 -0
- ciris_adapters/ciris_covenant_metrics/services.py +403 -0
- ciris_adapters/ciris_hosted_tools/__init__.py +24 -0
- ciris_adapters/ciris_hosted_tools/adapter.py +169 -0
- ciris_adapters/ciris_hosted_tools/manifest.json +94 -0
- ciris_adapters/ciris_hosted_tools/services.py +744 -0
- ciris_adapters/external_data_sql/README.md +559 -0
- ciris_adapters/external_data_sql/__init__.py +43 -0
- ciris_adapters/external_data_sql/adapter.py +144 -0
- ciris_adapters/external_data_sql/configurable.py +315 -0
- ciris_adapters/external_data_sql/dialects/__init__.py +37 -0
- ciris_adapters/external_data_sql/dialects/base.py +133 -0
- ciris_adapters/external_data_sql/dialects/mysql.py +63 -0
- ciris_adapters/external_data_sql/dialects/postgresql.py +59 -0
- ciris_adapters/external_data_sql/dialects/sqlite.py +62 -0
- ciris_adapters/external_data_sql/example_config.json +88 -0
- ciris_adapters/external_data_sql/example_privacy_schema.yaml +127 -0
- ciris_adapters/external_data_sql/manifest.json +195 -0
- ciris_adapters/external_data_sql/privacy_schema_loader.py +189 -0
- ciris_adapters/external_data_sql/protocol.py +101 -0
- ciris_adapters/external_data_sql/schemas.py +146 -0
- ciris_adapters/external_data_sql/service.py +1547 -0
- ciris_adapters/external_data_sql/service_old.py +492 -0
- ciris_adapters/home_assistant/__init__.py +63 -0
- ciris_adapters/home_assistant/adapter.py +201 -0
- ciris_adapters/home_assistant/communication_service.py +347 -0
- ciris_adapters/home_assistant/configurable.py +667 -0
- ciris_adapters/home_assistant/manifest.json +203 -0
- ciris_adapters/home_assistant/schemas.py +129 -0
- ciris_adapters/home_assistant/service.py +751 -0
- ciris_adapters/home_assistant/tool_service.py +441 -0
- ciris_adapters/mcp_client/__init__.py +82 -0
- ciris_adapters/mcp_client/adapter.py +847 -0
- ciris_adapters/mcp_client/config.py +280 -0
- ciris_adapters/mcp_client/configurable.py +422 -0
- ciris_adapters/mcp_client/manifest.json +185 -0
- ciris_adapters/mcp_client/mcp_communication_service.py +393 -0
- ciris_adapters/mcp_client/mcp_tool_service.py +463 -0
- ciris_adapters/mcp_client/mcp_wise_service.py +394 -0
- ciris_adapters/mcp_client/schemas.py +149 -0
- ciris_adapters/mcp_client/security.py +592 -0
- ciris_adapters/mcp_common/__init__.py +44 -0
- ciris_adapters/mcp_common/manifest.json +25 -0
- ciris_adapters/mcp_common/protocol.py +315 -0
- ciris_adapters/mcp_common/schemas.py +225 -0
- ciris_adapters/mcp_server/__init__.py +47 -0
- ciris_adapters/mcp_server/adapter.py +581 -0
- ciris_adapters/mcp_server/config.py +260 -0
- ciris_adapters/mcp_server/configurable.py +393 -0
- ciris_adapters/mcp_server/handlers.py +663 -0
- ciris_adapters/mcp_server/manifest.json +211 -0
- ciris_adapters/mcp_server/security.py +500 -0
- ciris_adapters/mock_llm/README.md +117 -0
- ciris_adapters/mock_llm/__init__.py +21 -0
- ciris_adapters/mock_llm/adapter.py +131 -0
- ciris_adapters/mock_llm/configurable.py +237 -0
- ciris_adapters/mock_llm/manifest.json +106 -0
- ciris_adapters/mock_llm/protocol.py +37 -0
- ciris_adapters/mock_llm/responses.py +520 -0
- ciris_adapters/mock_llm/responses_action_selection.py +1041 -0
- ciris_adapters/mock_llm/responses_epistemic.py +17 -0
- ciris_adapters/mock_llm/responses_feedback.py +27 -0
- ciris_adapters/mock_llm/schemas.py +35 -0
- ciris_adapters/mock_llm/service.py +294 -0
- ciris_adapters/navigation/__init__.py +21 -0
- ciris_adapters/navigation/adapter.py +129 -0
- ciris_adapters/navigation/configurable.py +239 -0
- ciris_adapters/navigation/manifest.json +104 -0
- ciris_adapters/navigation/service.py +487 -0
- ciris_adapters/reddit/README.md +132 -0
- ciris_adapters/reddit/REDDIT_ADAPTER_ANALYSIS.md +715 -0
- ciris_adapters/reddit/REDDIT_ADAPTER_SUMMARY.txt +278 -0
- ciris_adapters/reddit/REDDIT_ANALYSIS_INDEX.md +307 -0
- ciris_adapters/reddit/REDDIT_PRODUCTION_READINESS_PLAN.md +518 -0
- ciris_adapters/reddit/__init__.py +15 -0
- ciris_adapters/reddit/adapter.py +189 -0
- ciris_adapters/reddit/configurable.py +274 -0
- ciris_adapters/reddit/error_handler.py +307 -0
- ciris_adapters/reddit/manifest.json +218 -0
- ciris_adapters/reddit/observer.py +532 -0
- ciris_adapters/reddit/protocol.py +34 -0
- ciris_adapters/reddit/schemas.py +433 -0
- ciris_adapters/reddit/service.py +1471 -0
- ciris_adapters/sample_adapter/README.md +474 -0
- ciris_adapters/sample_adapter/__init__.py +45 -0
- ciris_adapters/sample_adapter/adapter.py +208 -0
- ciris_adapters/sample_adapter/configurable.py +469 -0
- ciris_adapters/sample_adapter/manifest.json +247 -0
- ciris_adapters/sample_adapter/services.py +486 -0
- ciris_adapters/weather/__init__.py +16 -0
- ciris_adapters/weather/adapter.py +130 -0
- ciris_adapters/weather/configurable.py +240 -0
- ciris_adapters/weather/manifest.json +156 -0
- ciris_adapters/weather/service.py +600 -0
- ciris_agent-1.7.7.dist-info/METADATA +284 -0
- ciris_agent-1.7.7.dist-info/RECORD +986 -0
- ciris_agent-1.7.7.dist-info/WHEEL +5 -0
- ciris_agent-1.7.7.dist-info/entry_points.txt +15 -0
- ciris_agent-1.7.7.dist-info/licenses/LICENSE +205 -0
- ciris_agent-1.7.7.dist-info/licenses/NOTICE +82 -0
- ciris_agent-1.7.7.dist-info/top_level.txt +4 -0
- ciris_engine/__init__.py +15 -0
- ciris_engine/ciris_templates/ally.yaml +632 -0
- ciris_engine/ciris_templates/default.yaml +411 -0
- ciris_engine/ciris_templates/echo-core.yaml +629 -0
- ciris_engine/ciris_templates/echo-speculative.yaml +764 -0
- ciris_engine/ciris_templates/echo.yaml +647 -0
- ciris_engine/ciris_templates/sage.yaml +332 -0
- ciris_engine/ciris_templates/scout.yaml +338 -0
- ciris_engine/ciris_templates/test.yaml +168 -0
- ciris_engine/cli.py +42 -0
- ciris_engine/config/CIRIS_SERVICES.json +19 -0
- ciris_engine/config/MODEL_CAPABILITIES.json +419 -0
- ciris_engine/config/PRICING_DATA.json +179 -0
- ciris_engine/config/__init__.py +50 -0
- ciris_engine/config/ciris_services.py +113 -0
- ciris_engine/config/model_capabilities.py +388 -0
- ciris_engine/config/pricing_models.py +276 -0
- ciris_engine/constants.py +35 -0
- ciris_engine/data/__init__.py +1 -0
- ciris_engine/data/covenant_1.0b.txt +978 -0
- ciris_engine/gui_static/11steps.svg +107 -0
- ciris_engine/gui_static/2x-schematics.png +0 -0
- ciris_engine/gui_static/404/index.html +1 -0
- ciris_engine/gui_static/404.html +1 -0
- ciris_engine/gui_static/_next/static/0edhkwDxd5UccTsCmtaBi/_buildManifest.js +1 -0
- ciris_engine/gui_static/_next/static/0edhkwDxd5UccTsCmtaBi/_ssgManifest.js +1 -0
- ciris_engine/gui_static/_next/static/U-3xTQao7hc2wnAi-Uekm/_buildManifest.js +1 -0
- ciris_engine/gui_static/_next/static/U-3xTQao7hc2wnAi-Uekm/_ssgManifest.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/3297-60e86ba0f8a7b040.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/3835-2aad4b7f5f8e4643.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/4499-99a0bc47de0b8975.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/4534-af88cd4ba6e99bff.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/4541-84b455f9e0dc4cfe.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/4789-61412711484754bb.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/6539-c6398bc9d7018430.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/704-8e827b26cc8c2d32.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/704-fb45d630f3192c6f.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/8072-de4952a2e6d2b33f.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/8315-b91d03a3949db0af.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/8386-f93a83ccbd789bd9.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/87c73c54-781a7f35148d5433.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/8903-fefea3339a02d41b.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/9090-e66485adf8d9d990.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/_not-found/page-a67d9808462c23b1.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/account/api-keys/page-2d7ee1583bbbd02e.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/account/api-keys/page-6a3c2bae6fe92b7b.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/account/consent/page-2ed3a035136bc4e8.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/account/consent/page-b2f5c91844a32422.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/account/page-25b90f89af3ea58c.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/account/page-b65d16c94ecaf69c.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/account/privacy/page-675b6d05c8f9184f.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/account/privacy/page-cbee2e1c8ab52145.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/account/settings/page-0f44da06697cf9f0.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/account/settings/page-563420253577edbf.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/adapters/page-1854631018bc32be.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/agents/page-8353752c176a7c70.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/agents/page-f61a529f110a6040.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/api-demo/page-7f19b9d20d39be28.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/api-demo/page-d1063938f249b8bd.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/audit/page-321b6728b8fff0bb.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/audit/page-ebac35ca961a1277.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/billing/page-6f3dc3bd02924f8e.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/billing/page-fa4a469f814c821a.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/comms/page-0d4f734269addd8f.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/comms/page-79227d426050089c.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/config/page-018d21d683b6e5bc.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/config/page-2aa5a5363ca2a371.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/consent/page-198373205fd316e2.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/consent/page-f2ca39e7713b13f8.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/dashboard/page-1dd5a196f643c60d.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/dashboard/page-530a04d3abbb8cda.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/docs/page-3193b06d094ab654.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/docs/page-330e996dedb87aba.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/layout-0a70f5fc460298b1.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/layout-21f2f99dd5b336e9.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/login/page-33240e6c6034a49d.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/login/page-68ffab6d54a7fdcd.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/logs/page-8a6167aecc4a475c.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/memory/page-9ca8c5d0056de3ff.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/memory/page-e961226941c18f81.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/page-6fdb065a787a4974.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/page-89f87d431be6064a.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/runtime/page-2e728b9c43aa164d.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/runtime/page-c7dd033dc40a72f0.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/services/page-ae9f0bdf11d01a95.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/services/page-b10feb79ca5d75e5.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/sessions/page-13ebe7ef1c16ae11.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/sessions/page-e6c82b16d617f785.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/setup/page-0beb5f5b5a5c20fc.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/setup/page-2595e729eae30c0e.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/status-dashboard/page-1037c987aecc3653.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/status-dashboard/page-2ffd147f6d3162ff.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/system/page-2c5798d58cafcd91.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/system/page-505b1ba4eceb01c3.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/test-auth/page-b0cad31d5cb1b2fa.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/test-auth/page-f3ecd7a8012df230.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/test-login/page-f35117fdc4105801.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/test-login/page-fb583a7924114906.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/test-sdk/page-50f116fd76935563.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/test-sdk/page-c37d8aa5ba623a44.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/tools/page-429aec7a707777ef.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/tools/page-5f705aad60e0c04e.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/users/page-13476b8b0f3808cc.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/users/page-7e500d154ed5bba4.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/wa/page-cc4a9d8a5cb44d08.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/app/wa/page-ec3e429efbc79230.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/framework-9d29490f5ba089ba.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/main-1f554952e47a82c4.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/main-app-26fa8aed029082e5.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/main-app-97b0486ef6bcef25.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/pages/_app-6ce685456e616eb2.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/pages/_error-d4bce98d93fe21e7.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- ciris_engine/gui_static/_next/static/chunks/webpack-fcebd240b7f8477d.js +1 -0
- ciris_engine/gui_static/_next/static/css/16b94b1fe0cc6e37.css +3 -0
- ciris_engine/gui_static/_next/static/css/77a24ceaae86deff.css +3 -0
- ciris_engine/gui_static/_next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- ciris_engine/gui_static/_next/static/media/747892c23ea88013-s.woff2 +0 -0
- ciris_engine/gui_static/_next/static/media/8d697b304b401681-s.woff2 +0 -0
- ciris_engine/gui_static/_next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- ciris_engine/gui_static/_next/static/media/9610d9e46709d722-s.woff2 +0 -0
- ciris_engine/gui_static/_next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- ciris_engine/gui_static/_next/static/media/d8298875641ec7d4-s.p.woff2 +0 -0
- ciris_engine/gui_static/account/api-keys/index.html +1 -0
- ciris_engine/gui_static/account/api-keys/index.txt +27 -0
- ciris_engine/gui_static/account/consent/index.html +1 -0
- ciris_engine/gui_static/account/consent/index.txt +27 -0
- ciris_engine/gui_static/account/index.html +1 -0
- ciris_engine/gui_static/account/index.txt +27 -0
- ciris_engine/gui_static/account/privacy/index.html +1 -0
- ciris_engine/gui_static/account/privacy/index.txt +27 -0
- ciris_engine/gui_static/account/settings/index.html +1 -0
- ciris_engine/gui_static/account/settings/index.txt +27 -0
- ciris_engine/gui_static/adapters/index.html +1 -0
- ciris_engine/gui_static/adapters/index.txt +27 -0
- ciris_engine/gui_static/agents/index.html +1 -0
- ciris_engine/gui_static/agents/index.txt +27 -0
- ciris_engine/gui_static/andrew-roberts-euBRXcx57T4-unsplash.jpg +0 -0
- ciris_engine/gui_static/api-demo/index.html +1 -0
- ciris_engine/gui_static/api-demo/index.txt +27 -0
- ciris_engine/gui_static/audit/index.html +1 -0
- ciris_engine/gui_static/audit/index.txt +27 -0
- ciris_engine/gui_static/billing/index.html +1 -0
- ciris_engine/gui_static/billing/index.txt +27 -0
- ciris_engine/gui_static/blurryinfo.png +0 -0
- ciris_engine/gui_static/chip-vincent-PkQDwfl9Flc-unsplash.jpg +0 -0
- ciris_engine/gui_static/ciris-architecture.svg +338 -0
- ciris_engine/gui_static/comms/index.html +1 -0
- ciris_engine/gui_static/comms/index.txt +27 -0
- ciris_engine/gui_static/config/index.html +1 -0
- ciris_engine/gui_static/config/index.txt +27 -0
- ciris_engine/gui_static/consent/index.html +1 -0
- ciris_engine/gui_static/consent/index.txt +27 -0
- ciris_engine/gui_static/dashboard/index.html +1 -0
- ciris_engine/gui_static/dashboard/index.txt +27 -0
- ciris_engine/gui_static/docs/index.html +1 -0
- ciris_engine/gui_static/docs/index.txt +27 -0
- ciris_engine/gui_static/eric.png +0 -0
- ciris_engine/gui_static/file.svg +1 -0
- ciris_engine/gui_static/globe.svg +1 -0
- ciris_engine/gui_static/index.html +1 -0
- ciris_engine/gui_static/index.txt +27 -0
- ciris_engine/gui_static/infogfx-1@2x.png +0 -0
- ciris_engine/gui_static/infogfx-2.png +0 -0
- ciris_engine/gui_static/infogfx-dark-1.png +0 -0
- ciris_engine/gui_static/kelly-vohs-soSTXmIxTDU-unsplash.jpg +0 -0
- ciris_engine/gui_static/login/index.html +1 -0
- ciris_engine/gui_static/login/index.txt +27 -0
- ciris_engine/gui_static/logs/index.html +1 -0
- ciris_engine/gui_static/logs/index.txt +27 -0
- ciris_engine/gui_static/memory/index.html +1 -0
- ciris_engine/gui_static/memory/index.txt +27 -0
- ciris_engine/gui_static/nathan-farrish-ArcTfEoBgzs-unsplash.jpg +0 -0
- ciris_engine/gui_static/next.svg +1 -0
- ciris_engine/gui_static/overview.svg +512 -0
- ciris_engine/gui_static/overview1.svg +407 -0
- ciris_engine/gui_static/overview2.svg +370 -0
- ciris_engine/gui_static/pipeline-visualization.svg +278 -0
- ciris_engine/gui_static/privacy-policy.html +160 -0
- ciris_engine/gui_static/runtime/index.html +8 -0
- ciris_engine/gui_static/runtime/index.txt +27 -0
- ciris_engine/gui_static/services/index.html +1 -0
- ciris_engine/gui_static/services/index.txt +27 -0
- ciris_engine/gui_static/sessions/index.html +1 -0
- ciris_engine/gui_static/sessions/index.txt +27 -0
- ciris_engine/gui_static/setup/index.html +1 -0
- ciris_engine/gui_static/setup/index.txt +27 -0
- ciris_engine/gui_static/status-dashboard/index.html +1 -0
- ciris_engine/gui_static/status-dashboard/index.txt +27 -0
- ciris_engine/gui_static/system/index.html +1 -0
- ciris_engine/gui_static/system/index.txt +27 -0
- ciris_engine/gui_static/terms-of-service.html +174 -0
- ciris_engine/gui_static/test-auth/index.html +1 -0
- ciris_engine/gui_static/test-auth/index.txt +27 -0
- ciris_engine/gui_static/test-login/index.html +1 -0
- ciris_engine/gui_static/test-login/index.txt +27 -0
- ciris_engine/gui_static/test-sdk/index.html +1 -0
- ciris_engine/gui_static/test-sdk/index.txt +27 -0
- ciris_engine/gui_static/tools/index.html +1 -0
- ciris_engine/gui_static/tools/index.txt +27 -0
- ciris_engine/gui_static/users/index.html +1 -0
- ciris_engine/gui_static/users/index.txt +27 -0
- ciris_engine/gui_static/vercel.svg +1 -0
- ciris_engine/gui_static/videos/video1.mp4 +0 -0
- ciris_engine/gui_static/videos/video3.mp4 +0 -0
- ciris_engine/gui_static/wa/index.html +1 -0
- ciris_engine/gui_static/wa/index.txt +27 -0
- ciris_engine/gui_static/window.svg +1 -0
- ciris_engine/logic/__init__.py +8 -0
- ciris_engine/logic/adapters/__init__.py +74 -0
- ciris_engine/logic/adapters/api/__init__.py +5 -0
- ciris_engine/logic/adapters/api/adapter.py +1037 -0
- ciris_engine/logic/adapters/api/api_communication.py +370 -0
- ciris_engine/logic/adapters/api/api_document.py +330 -0
- ciris_engine/logic/adapters/api/api_observer.py +24 -0
- ciris_engine/logic/adapters/api/api_runtime_control.py +388 -0
- ciris_engine/logic/adapters/api/api_tools.py +299 -0
- ciris_engine/logic/adapters/api/api_vision.py +215 -0
- ciris_engine/logic/adapters/api/app.py +272 -0
- ciris_engine/logic/adapters/api/auth.py +159 -0
- ciris_engine/logic/adapters/api/config.py +101 -0
- ciris_engine/logic/adapters/api/constants.py +55 -0
- ciris_engine/logic/adapters/api/dependencies/__init__.py +1 -0
- ciris_engine/logic/adapters/api/dependencies/auth.py +260 -0
- ciris_engine/logic/adapters/api/endpoints/__init__.py +1 -0
- ciris_engine/logic/adapters/api/endpoints/emergency.py +86 -0
- ciris_engine/logic/adapters/api/middleware/__init__.py +1 -0
- ciris_engine/logic/adapters/api/middleware/rate_limiter.py +302 -0
- ciris_engine/logic/adapters/api/models.py +29 -0
- ciris_engine/logic/adapters/api/routes/__init__.py +52 -0
- ciris_engine/logic/adapters/api/routes/agent.py +1762 -0
- ciris_engine/logic/adapters/api/routes/audit.py +707 -0
- ciris_engine/logic/adapters/api/routes/auth.py +1745 -0
- ciris_engine/logic/adapters/api/routes/billing.py +895 -0
- ciris_engine/logic/adapters/api/routes/config.py +329 -0
- ciris_engine/logic/adapters/api/routes/connectors.py +534 -0
- ciris_engine/logic/adapters/api/routes/consent.py +637 -0
- ciris_engine/logic/adapters/api/routes/dsar.py +637 -0
- ciris_engine/logic/adapters/api/routes/dsar_multi_source.py +484 -0
- ciris_engine/logic/adapters/api/routes/emergency.py +302 -0
- ciris_engine/logic/adapters/api/routes/memory.py +733 -0
- ciris_engine/logic/adapters/api/routes/memory_filters.py +230 -0
- ciris_engine/logic/adapters/api/routes/memory_models.py +112 -0
- ciris_engine/logic/adapters/api/routes/memory_queries.py +236 -0
- ciris_engine/logic/adapters/api/routes/memory_query_helpers.py +394 -0
- ciris_engine/logic/adapters/api/routes/memory_visualization.py +359 -0
- ciris_engine/logic/adapters/api/routes/memory_visualization_helpers.py +110 -0
- ciris_engine/logic/adapters/api/routes/partnership.py +541 -0
- ciris_engine/logic/adapters/api/routes/setup.py +1374 -0
- ciris_engine/logic/adapters/api/routes/system.py +3049 -0
- ciris_engine/logic/adapters/api/routes/system_extensions.py +952 -0
- ciris_engine/logic/adapters/api/routes/telemetry.py +1987 -0
- ciris_engine/logic/adapters/api/routes/telemetry_converters.py +141 -0
- ciris_engine/logic/adapters/api/routes/telemetry_helpers.py +111 -0
- ciris_engine/logic/adapters/api/routes/telemetry_logs_reader.py +280 -0
- ciris_engine/logic/adapters/api/routes/telemetry_metrics.py +131 -0
- ciris_engine/logic/adapters/api/routes/telemetry_models.py +190 -0
- ciris_engine/logic/adapters/api/routes/telemetry_otlp.py +878 -0
- ciris_engine/logic/adapters/api/routes/telemetry_resource_helpers.py +191 -0
- ciris_engine/logic/adapters/api/routes/tickets.py +541 -0
- ciris_engine/logic/adapters/api/routes/tools.py +556 -0
- ciris_engine/logic/adapters/api/routes/transparency.py +281 -0
- ciris_engine/logic/adapters/api/routes/users.py +981 -0
- ciris_engine/logic/adapters/api/routes/verification.py +373 -0
- ciris_engine/logic/adapters/api/routes/wa.py +369 -0
- ciris_engine/logic/adapters/api/service_configuration.py +177 -0
- ciris_engine/logic/adapters/api/services/__init__.py +1 -0
- ciris_engine/logic/adapters/api/services/auth_service.py +1417 -0
- ciris_engine/logic/adapters/api/services/oauth_security.py +68 -0
- ciris_engine/logic/adapters/base.py +141 -0
- ciris_engine/logic/adapters/base_adapter.py +73 -0
- ciris_engine/logic/adapters/base_observer.py +1141 -0
- ciris_engine/logic/adapters/base_vision.py +312 -0
- ciris_engine/logic/adapters/cirisnode_client.py +307 -0
- ciris_engine/logic/adapters/cli/__init__.py +3 -0
- ciris_engine/logic/adapters/cli/adapter.py +207 -0
- ciris_engine/logic/adapters/cli/cli_adapter.py +902 -0
- ciris_engine/logic/adapters/cli/cli_observer.py +268 -0
- ciris_engine/logic/adapters/cli/cli_tools.py +427 -0
- ciris_engine/logic/adapters/cli/cli_wa_service.py +134 -0
- ciris_engine/logic/adapters/cli/config.py +73 -0
- ciris_engine/logic/adapters/discord/__init__.py +3 -0
- ciris_engine/logic/adapters/discord/adapter.py +783 -0
- ciris_engine/logic/adapters/discord/ciris_discord_client.py +159 -0
- ciris_engine/logic/adapters/discord/config.py +177 -0
- ciris_engine/logic/adapters/discord/constants.py +185 -0
- ciris_engine/logic/adapters/discord/discord-stubs.pyi +50 -0
- ciris_engine/logic/adapters/discord/discord_adapter.py +1584 -0
- ciris_engine/logic/adapters/discord/discord_audit.py +150 -0
- ciris_engine/logic/adapters/discord/discord_channel_manager.py +351 -0
- ciris_engine/logic/adapters/discord/discord_connection_manager.py +313 -0
- ciris_engine/logic/adapters/discord/discord_embed_formatter.py +369 -0
- ciris_engine/logic/adapters/discord/discord_error_classifier.py +302 -0
- ciris_engine/logic/adapters/discord/discord_error_handler.py +316 -0
- ciris_engine/logic/adapters/discord/discord_guidance_handler.py +460 -0
- ciris_engine/logic/adapters/discord/discord_message_handler.py +207 -0
- ciris_engine/logic/adapters/discord/discord_observer.py +670 -0
- ciris_engine/logic/adapters/discord/discord_rate_limiter.py +249 -0
- ciris_engine/logic/adapters/discord/discord_reaction_handler.py +278 -0
- ciris_engine/logic/adapters/discord/discord_tool_handler.py +465 -0
- ciris_engine/logic/adapters/discord/discord_tool_service.py +790 -0
- ciris_engine/logic/adapters/discord/discord_tools.py +90 -0
- ciris_engine/logic/adapters/discord/discord_vision_helper.py +148 -0
- ciris_engine/logic/adapters/discord/py.typed +0 -0
- ciris_engine/logic/adapters/document_parser.py +320 -0
- ciris_engine/logic/audit/__init__.py +10 -0
- ciris_engine/logic/audit/hash_chain.py +313 -0
- ciris_engine/logic/audit/signature_manager.py +352 -0
- ciris_engine/logic/audit/verifier.py +408 -0
- ciris_engine/logic/buses/__init__.py +21 -0
- ciris_engine/logic/buses/base_bus.py +178 -0
- ciris_engine/logic/buses/bus_manager.py +121 -0
- ciris_engine/logic/buses/communication_bus.py +387 -0
- ciris_engine/logic/buses/llm_bus.py +722 -0
- ciris_engine/logic/buses/memory_bus.py +577 -0
- ciris_engine/logic/buses/prohibitions.py +502 -0
- ciris_engine/logic/buses/runtime_control_bus.py +539 -0
- ciris_engine/logic/buses/tool_bus.py +482 -0
- ciris_engine/logic/buses/wise_bus.py +684 -0
- ciris_engine/logic/config/__init__.py +25 -0
- ciris_engine/logic/config/bootstrap.py +255 -0
- ciris_engine/logic/config/config_accessor.py +202 -0
- ciris_engine/logic/config/db_paths.py +194 -0
- ciris_engine/logic/config/env_utils.py +39 -0
- ciris_engine/logic/conscience/__init__.py +16 -0
- ciris_engine/logic/conscience/build_deferral_package.py +0 -0
- ciris_engine/logic/conscience/core.py +688 -0
- ciris_engine/logic/conscience/interface.py +33 -0
- ciris_engine/logic/conscience/registry.py +76 -0
- ciris_engine/logic/conscience/thought_depth_guardrail.py +231 -0
- ciris_engine/logic/conscience/updated_status_conscience.py +156 -0
- ciris_engine/logic/context/__init__.py +10 -0
- ciris_engine/logic/context/batch_context.py +550 -0
- ciris_engine/logic/context/builder.py +149 -0
- ciris_engine/logic/context/channel_resolution.py +136 -0
- ciris_engine/logic/context/secrets_snapshot.py +52 -0
- ciris_engine/logic/context/system_snapshot.py +116 -0
- ciris_engine/logic/context/system_snapshot_helpers.py +1651 -0
- ciris_engine/logic/covenant/__init__.py +33 -0
- ciris_engine/logic/covenant/executor.py +303 -0
- ciris_engine/logic/covenant/extractor.py +382 -0
- ciris_engine/logic/covenant/handler.py +241 -0
- ciris_engine/logic/covenant/verifier.py +383 -0
- ciris_engine/logic/dma/__init__.py +15 -0
- ciris_engine/logic/dma/action_selection/__init__.py +11 -0
- ciris_engine/logic/dma/action_selection/action_instruction_generator.py +444 -0
- ciris_engine/logic/dma/action_selection/context_builder.py +508 -0
- ciris_engine/logic/dma/action_selection/faculty_integration.py +193 -0
- ciris_engine/logic/dma/action_selection/special_cases.py +132 -0
- ciris_engine/logic/dma/action_selection_pdma.py +365 -0
- ciris_engine/logic/dma/base_dma.py +335 -0
- ciris_engine/logic/dma/csdma.py +239 -0
- ciris_engine/logic/dma/dma_executor.py +575 -0
- ciris_engine/logic/dma/dsdma_base.py +410 -0
- ciris_engine/logic/dma/exceptions.py +4 -0
- ciris_engine/logic/dma/factory.py +150 -0
- ciris_engine/logic/dma/pdma.py +120 -0
- ciris_engine/logic/dma/prompt_loader.py +189 -0
- ciris_engine/logic/dma/prompts/action_selection_pdma.yml +58 -0
- ciris_engine/logic/dma/prompts/csdma_common_sense.yml +28 -0
- ciris_engine/logic/dma/prompts/dsdma_base.yml +17 -0
- ciris_engine/logic/dma/prompts/pdma_ethical.yml +42 -0
- ciris_engine/logic/formatters/__init__.py +26 -0
- ciris_engine/logic/formatters/crisis_resources.py +80 -0
- ciris_engine/logic/formatters/escalation.py +21 -0
- ciris_engine/logic/formatters/identity.py +224 -0
- ciris_engine/logic/formatters/prompt_blocks.py +64 -0
- ciris_engine/logic/formatters/system_snapshot.py +193 -0
- ciris_engine/logic/formatters/user_profiles.py +108 -0
- ciris_engine/logic/handlers/__init__.py +1 -0
- ciris_engine/logic/handlers/control/__init__.py +1 -0
- ciris_engine/logic/handlers/control/defer_handler.py +195 -0
- ciris_engine/logic/handlers/control/ponder_handler.py +154 -0
- ciris_engine/logic/handlers/control/reject_handler.py +81 -0
- ciris_engine/logic/handlers/external/__init__.py +1 -0
- ciris_engine/logic/handlers/external/observe_handler.py +154 -0
- ciris_engine/logic/handlers/external/speak_handler.py +250 -0
- ciris_engine/logic/handlers/external/tool_handler.py +148 -0
- ciris_engine/logic/handlers/memory/__init__.py +1 -0
- ciris_engine/logic/handlers/memory/forget_handler.py +107 -0
- ciris_engine/logic/handlers/memory/memorize_handler.py +391 -0
- ciris_engine/logic/handlers/memory/recall_handler.py +213 -0
- ciris_engine/logic/handlers/terminal/__init__.py +1 -0
- ciris_engine/logic/handlers/terminal/task_complete_handler.py +299 -0
- ciris_engine/logic/infrastructure/__init__.py +1 -0
- ciris_engine/logic/infrastructure/handlers/__init__.py +8 -0
- ciris_engine/logic/infrastructure/handlers/action_dispatcher.py +382 -0
- ciris_engine/logic/infrastructure/handlers/base_handler.py +450 -0
- ciris_engine/logic/infrastructure/handlers/exceptions.py +2 -0
- ciris_engine/logic/infrastructure/handlers/handler_registry.py +59 -0
- ciris_engine/logic/infrastructure/handlers/helpers.py +55 -0
- ciris_engine/logic/infrastructure/step_streaming.py +149 -0
- ciris_engine/logic/infrastructure/sub_services/__init__.py +1 -0
- ciris_engine/logic/infrastructure/sub_services/identity_variance_monitor.py +1035 -0
- ciris_engine/logic/infrastructure/sub_services/pattern_analysis_loop.py +758 -0
- ciris_engine/logic/infrastructure/sub_services/wa_cli_bootstrap.py +229 -0
- ciris_engine/logic/infrastructure/sub_services/wa_cli_display.py +176 -0
- ciris_engine/logic/infrastructure/sub_services/wa_cli_oauth.py +404 -0
- ciris_engine/logic/infrastructure/sub_services/wa_cli_wizard.py +181 -0
- ciris_engine/logic/persistence/__init__.py +130 -0
- ciris_engine/logic/persistence/analytics.py +97 -0
- ciris_engine/logic/persistence/db/__init__.py +28 -0
- ciris_engine/logic/persistence/db/core.py +520 -0
- ciris_engine/logic/persistence/db/dialect.py +380 -0
- ciris_engine/logic/persistence/db/execution_helpers.py +216 -0
- ciris_engine/logic/persistence/db/migration_runner.py +191 -0
- ciris_engine/logic/persistence/db/operations.py +313 -0
- ciris_engine/logic/persistence/db/query_builder.py +232 -0
- ciris_engine/logic/persistence/db/retry.py +154 -0
- ciris_engine/logic/persistence/db/setup.py +18 -0
- ciris_engine/logic/persistence/migrations/postgres/001_initial_schema.sql +4 -0
- ciris_engine/logic/persistence/migrations/postgres/002_add_retry_status.sql +3 -0
- ciris_engine/logic/persistence/migrations/postgres/003_add_task_update_tracking.sql +8 -0
- ciris_engine/logic/persistence/migrations/postgres/004_add_occurrence_id.sql +54 -0
- ciris_engine/logic/persistence/migrations/postgres/005_add_consolidation_locks.sql +22 -0
- ciris_engine/logic/persistence/migrations/postgres/006_add_correlation_id_unique_index.sql +16 -0
- ciris_engine/logic/persistence/migrations/postgres/007_add_dsar_tickets.sql +39 -0
- ciris_engine/logic/persistence/migrations/postgres/008_rename_to_tickets_add_sop.sql +123 -0
- ciris_engine/logic/persistence/migrations/postgres/009_add_ticket_status_columns.sql +39 -0
- ciris_engine/logic/persistence/migrations/postgres/010_add_images_to_tasks.sql +5 -0
- ciris_engine/logic/persistence/migrations/sqlite/001_initial_schema.sql +357 -0
- ciris_engine/logic/persistence/migrations/sqlite/002_add_retry_status.sql +3 -0
- ciris_engine/logic/persistence/migrations/sqlite/003_add_task_update_tracking.sql +8 -0
- ciris_engine/logic/persistence/migrations/sqlite/004_add_occurrence_id.sql +45 -0
- ciris_engine/logic/persistence/migrations/sqlite/005_add_consolidation_locks.sql +22 -0
- ciris_engine/logic/persistence/migrations/sqlite/006_add_correlation_id_unique_index.sql +16 -0
- ciris_engine/logic/persistence/migrations/sqlite/007_add_dsar_tickets.sql +39 -0
- ciris_engine/logic/persistence/migrations/sqlite/008_rename_to_tickets_add_sop.sql +120 -0
- ciris_engine/logic/persistence/migrations/sqlite/009_add_ticket_status_columns.sql +129 -0
- ciris_engine/logic/persistence/migrations/sqlite/010_add_images_to_tasks.sql +17 -0
- ciris_engine/logic/persistence/models/__init__.py +141 -0
- ciris_engine/logic/persistence/models/correlations.py +881 -0
- ciris_engine/logic/persistence/models/deferral.py +68 -0
- ciris_engine/logic/persistence/models/dsar.py +286 -0
- ciris_engine/logic/persistence/models/graph.py +362 -0
- ciris_engine/logic/persistence/models/identity.py +264 -0
- ciris_engine/logic/persistence/models/queue_status.py +139 -0
- ciris_engine/logic/persistence/models/tasks.py +1043 -0
- ciris_engine/logic/persistence/models/thoughts.py +400 -0
- ciris_engine/logic/persistence/models/tickets.py +518 -0
- ciris_engine/logic/persistence/stores/__init__.py +13 -0
- ciris_engine/logic/persistence/stores/auth_helpers.py +117 -0
- ciris_engine/logic/persistence/stores/authentication_store.py +414 -0
- ciris_engine/logic/persistence/utils.py +212 -0
- ciris_engine/logic/processors/__init__.py +30 -0
- ciris_engine/logic/processors/core/__init__.py +1 -0
- ciris_engine/logic/processors/core/base_processor.py +280 -0
- ciris_engine/logic/processors/core/main_processor.py +1777 -0
- ciris_engine/logic/processors/core/step_decorators.py +1583 -0
- ciris_engine/logic/processors/core/thought_processor/__init__.py +20 -0
- ciris_engine/logic/processors/core/thought_processor/action_execution.py +49 -0
- ciris_engine/logic/processors/core/thought_processor/conscience_execution.py +382 -0
- ciris_engine/logic/processors/core/thought_processor/finalize_action.py +66 -0
- ciris_engine/logic/processors/core/thought_processor/gather_context.py +120 -0
- ciris_engine/logic/processors/core/thought_processor/main.py +920 -0
- ciris_engine/logic/processors/core/thought_processor/perform_aspdma.py +86 -0
- ciris_engine/logic/processors/core/thought_processor/perform_dmas.py +106 -0
- ciris_engine/logic/processors/core/thought_processor/recursive_processing.py +237 -0
- ciris_engine/logic/processors/core/thought_processor/round_complete.py +52 -0
- ciris_engine/logic/processors/core/thought_processor/start_round.py +64 -0
- ciris_engine/logic/processors/exceptions.py +59 -0
- ciris_engine/logic/processors/states/__init__.py +1 -0
- ciris_engine/logic/processors/states/dream_processor.py +1381 -0
- ciris_engine/logic/processors/states/play_processor.py +141 -0
- ciris_engine/logic/processors/states/shutdown_processor.py +623 -0
- ciris_engine/logic/processors/states/solitude_processor.py +305 -0
- ciris_engine/logic/processors/states/wakeup_processor.py +802 -0
- ciris_engine/logic/processors/states/work_processor.py +742 -0
- ciris_engine/logic/processors/support/__init__.py +1 -0
- ciris_engine/logic/processors/support/dma_orchestrator.py +336 -0
- ciris_engine/logic/processors/support/processing_queue.py +133 -0
- ciris_engine/logic/processors/support/shutdown_condition_evaluator.py +294 -0
- ciris_engine/logic/processors/support/state_manager.py +358 -0
- ciris_engine/logic/processors/support/task_manager.py +303 -0
- ciris_engine/logic/processors/support/thought_escalation.py +116 -0
- ciris_engine/logic/processors/support/thought_manager.py +328 -0
- ciris_engine/logic/processors/support/thought_manager_enhanced.py +105 -0
- ciris_engine/logic/registries/__init__.py +34 -0
- ciris_engine/logic/registries/base.py +653 -0
- ciris_engine/logic/registries/circuit_breaker.py +275 -0
- ciris_engine/logic/registries/typed_registries.py +184 -0
- ciris_engine/logic/runtime/__init__.py +7 -0
- ciris_engine/logic/runtime/adapter_loader.py +261 -0
- ciris_engine/logic/runtime/adapter_manager.py +1053 -0
- ciris_engine/logic/runtime/ciris_runtime.py +2342 -0
- ciris_engine/logic/runtime/ciris_runtime_helpers.py +923 -0
- ciris_engine/logic/runtime/component_builder.py +361 -0
- ciris_engine/logic/runtime/identity_manager.py +219 -0
- ciris_engine/logic/runtime/module_loader.py +207 -0
- ciris_engine/logic/runtime/prevent_sideeffects.py +30 -0
- ciris_engine/logic/runtime/runtime_interface.py +23 -0
- ciris_engine/logic/runtime/service_initializer.py +1623 -0
- ciris_engine/logic/secrets/__init__.py +30 -0
- ciris_engine/logic/secrets/encryption.py +175 -0
- ciris_engine/logic/secrets/filter.py +295 -0
- ciris_engine/logic/secrets/service.py +652 -0
- ciris_engine/logic/secrets/store.py +669 -0
- ciris_engine/logic/services/__init__.py +1 -0
- ciris_engine/logic/services/adaptation/__init__.py +3 -0
- ciris_engine/logic/services/base_graph_service.py +142 -0
- ciris_engine/logic/services/base_infrastructure_service.py +69 -0
- ciris_engine/logic/services/base_scheduled_service.py +136 -0
- ciris_engine/logic/services/base_service.py +247 -0
- ciris_engine/logic/services/governance/__init__.py +3 -0
- ciris_engine/logic/services/governance/adaptive_filter/__init__.py +14 -0
- ciris_engine/logic/services/governance/adaptive_filter/service.py +818 -0
- ciris_engine/logic/services/governance/consent/__init__.py +53 -0
- ciris_engine/logic/services/governance/consent/air.py +403 -0
- ciris_engine/logic/services/governance/consent/decay.py +324 -0
- ciris_engine/logic/services/governance/consent/dsar_automation.py +589 -0
- ciris_engine/logic/services/governance/consent/exceptions.py +106 -0
- ciris_engine/logic/services/governance/consent/metrics.py +270 -0
- ciris_engine/logic/services/governance/consent/partnership.py +533 -0
- ciris_engine/logic/services/governance/consent/service.py +1256 -0
- ciris_engine/logic/services/governance/dsar/__init__.py +29 -0
- ciris_engine/logic/services/governance/dsar/orchestrator.py +977 -0
- ciris_engine/logic/services/governance/dsar/schemas.py +141 -0
- ciris_engine/logic/services/governance/dsar/signature_service.py +283 -0
- ciris_engine/logic/services/governance/self_observation/__init__.py +20 -0
- ciris_engine/logic/services/governance/self_observation/service.py +1153 -0
- ciris_engine/logic/services/governance/visibility/__init__.py +17 -0
- ciris_engine/logic/services/governance/visibility/service.py +512 -0
- ciris_engine/logic/services/governance/wise_authority/__init__.py +15 -0
- ciris_engine/logic/services/governance/wise_authority/service.py +827 -0
- ciris_engine/logic/services/graph/__init__.py +5 -0
- ciris_engine/logic/services/graph/audit_service/__init__.py +5 -0
- ciris_engine/logic/services/graph/audit_service/service.py +1675 -0
- ciris_engine/logic/services/graph/base.py +208 -0
- ciris_engine/logic/services/graph/config_service/__init__.py +5 -0
- ciris_engine/logic/services/graph/config_service/service.py +372 -0
- ciris_engine/logic/services/graph/incident_service/__init__.py +5 -0
- ciris_engine/logic/services/graph/incident_service/service.py +803 -0
- ciris_engine/logic/services/graph/memory_service.py +1120 -0
- ciris_engine/logic/services/graph/telemetry_service/__init__.py +5 -0
- ciris_engine/logic/services/graph/telemetry_service/exceptions.py +104 -0
- ciris_engine/logic/services/graph/telemetry_service/helpers.py +1337 -0
- ciris_engine/logic/services/graph/telemetry_service/service.py +2429 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/__init__.py +17 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/aggregation_helpers.py +355 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/cleanup_helpers.py +438 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/compressor.py +260 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/__init__.py +27 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/audit.py +326 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/conversation.py +291 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/memory.py +197 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/metrics.py +251 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/task.py +257 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/trace.py +363 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/data_converter.py +545 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/date_calculation_helpers.py +193 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/db_query_helpers.py +296 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/edge_helpers.py +92 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/edge_manager.py +896 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/extensive_helpers.py +322 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/period_manager.py +152 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/profound_helpers.py +277 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/query_manager.py +812 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/service.py +1692 -0
- ciris_engine/logic/services/graph/tsdb_consolidation/sql_builders.py +363 -0
- ciris_engine/logic/services/infrastructure/__init__.py +1 -0
- ciris_engine/logic/services/infrastructure/authentication/__init__.py +5 -0
- ciris_engine/logic/services/infrastructure/authentication/service.py +1634 -0
- ciris_engine/logic/services/infrastructure/database_maintenance/__init__.py +15 -0
- ciris_engine/logic/services/infrastructure/database_maintenance/service.py +764 -0
- ciris_engine/logic/services/infrastructure/resource_monitor/__init__.py +7 -0
- ciris_engine/logic/services/infrastructure/resource_monitor/ciris_billing_provider.py +755 -0
- ciris_engine/logic/services/infrastructure/resource_monitor/service.py +409 -0
- ciris_engine/logic/services/infrastructure/resource_monitor/simple_credit_provider.py +129 -0
- ciris_engine/logic/services/lifecycle/__init__.py +3 -0
- ciris_engine/logic/services/lifecycle/initialization/__init__.py +10 -0
- ciris_engine/logic/services/lifecycle/initialization/service.py +312 -0
- ciris_engine/logic/services/lifecycle/scheduler/__init__.py +5 -0
- ciris_engine/logic/services/lifecycle/scheduler/service.py +607 -0
- ciris_engine/logic/services/lifecycle/shutdown/__init__.py +9 -0
- ciris_engine/logic/services/lifecycle/shutdown/service.py +378 -0
- ciris_engine/logic/services/lifecycle/time/__init__.py +15 -0
- ciris_engine/logic/services/lifecycle/time/service.py +259 -0
- ciris_engine/logic/services/memory_service/__init__.py +8 -0
- ciris_engine/logic/services/mixins/__init__.py +13 -0
- ciris_engine/logic/services/mixins/example_usage.py +200 -0
- ciris_engine/logic/services/mixins/request_metrics.py +179 -0
- ciris_engine/logic/services/runtime/__init__.py +3 -0
- ciris_engine/logic/services/runtime/adapter_configuration/__init__.py +16 -0
- ciris_engine/logic/services/runtime/adapter_configuration/service.py +674 -0
- ciris_engine/logic/services/runtime/adapter_configuration/session.py +67 -0
- ciris_engine/logic/services/runtime/control_service/__init__.py +5 -0
- ciris_engine/logic/services/runtime/control_service/service.py +2269 -0
- ciris_engine/logic/services/runtime/llm_service/__init__.py +14 -0
- ciris_engine/logic/services/runtime/llm_service/pricing_calculator.py +279 -0
- ciris_engine/logic/services/runtime/llm_service/service.py +930 -0
- ciris_engine/logic/services/tools/__init__.py +5 -0
- ciris_engine/logic/services/tools/core_tool_service/__init__.py +8 -0
- ciris_engine/logic/services/tools/core_tool_service/service.py +852 -0
- ciris_engine/logic/setup/__init__.py +1 -0
- ciris_engine/logic/setup/first_run.py +250 -0
- ciris_engine/logic/setup/wizard.py +327 -0
- ciris_engine/logic/telemetry/__init__.py +46 -0
- ciris_engine/logic/telemetry/core.py +239 -0
- ciris_engine/logic/telemetry/hot_cold_config.py +133 -0
- ciris_engine/logic/telemetry/log_collector.py +190 -0
- ciris_engine/logic/telemetry/resource_monitor.py +7 -0
- ciris_engine/logic/telemetry/security.py +79 -0
- ciris_engine/logic/utils/__init__.py +18 -0
- ciris_engine/logic/utils/channel_utils.py +75 -0
- ciris_engine/logic/utils/consent/__init__.py +1 -0
- ciris_engine/logic/utils/consent/partnership_utils.py +172 -0
- ciris_engine/logic/utils/constants.py +92 -0
- ciris_engine/logic/utils/context_utils.py +145 -0
- ciris_engine/logic/utils/directory_setup.py +533 -0
- ciris_engine/logic/utils/graphql_context_provider.py +152 -0
- ciris_engine/logic/utils/identity_resolution.py +843 -0
- ciris_engine/logic/utils/incident_capture_handler.py +303 -0
- ciris_engine/logic/utils/initialization_manager.py +74 -0
- ciris_engine/logic/utils/jsondict_helpers.py +290 -0
- ciris_engine/logic/utils/log_sanitizer.py +97 -0
- ciris_engine/logic/utils/logging_config.py +151 -0
- ciris_engine/logic/utils/observability_decorators.py +544 -0
- ciris_engine/logic/utils/occurrence_utils.py +155 -0
- ciris_engine/logic/utils/path_resolution.py +281 -0
- ciris_engine/logic/utils/platform_detection.py +286 -0
- ciris_engine/logic/utils/privacy.py +266 -0
- ciris_engine/logic/utils/profile_loader.py +124 -0
- ciris_engine/logic/utils/profile_manager.py +16 -0
- ciris_engine/logic/utils/runtime_utils.py +69 -0
- ciris_engine/logic/utils/shutdown_manager.py +107 -0
- ciris_engine/logic/utils/task_formatters.py +60 -0
- ciris_engine/logic/utils/task_thought_factory.py +404 -0
- ciris_engine/logic/utils/thought_utils.py +54 -0
- ciris_engine/logic/utils/user_utils.py +70 -0
- ciris_engine/protocols/__init__.py +0 -0
- ciris_engine/protocols/adapters/__init__.py +35 -0
- ciris_engine/protocols/adapters/base.py +149 -0
- ciris_engine/protocols/adapters/configurable.py +265 -0
- ciris_engine/protocols/adapters/message.py +90 -0
- ciris_engine/protocols/audit/__init__.py +1 -0
- ciris_engine/protocols/buses/__init__.py +1 -0
- ciris_engine/protocols/config/__init__.py +1 -0
- ciris_engine/protocols/conscience/__init__.py +1 -0
- ciris_engine/protocols/consent.py +88 -0
- ciris_engine/protocols/context/__init__.py +1 -0
- ciris_engine/protocols/data/__init__.py +1 -0
- ciris_engine/protocols/dma/__init__.py +1 -0
- ciris_engine/protocols/dma/base.py +107 -0
- ciris_engine/protocols/faculties.py +34 -0
- ciris_engine/protocols/formatters/__init__.py +1 -0
- ciris_engine/protocols/handlers/__init__.py +1 -0
- ciris_engine/protocols/infrastructure/__init__.py +25 -0
- ciris_engine/protocols/infrastructure/base.py +377 -0
- ciris_engine/protocols/persistence/__init__.py +1 -0
- ciris_engine/protocols/pipeline_control.py +609 -0
- ciris_engine/protocols/processors/__init__.py +19 -0
- ciris_engine/protocols/processors/agent.py +299 -0
- ciris_engine/protocols/processors/base.py +130 -0
- ciris_engine/protocols/processors/orchestration.py +62 -0
- ciris_engine/protocols/registries/__init__.py +1 -0
- ciris_engine/protocols/runtime/__init__.py +1 -0
- ciris_engine/protocols/runtime/base.py +163 -0
- ciris_engine/protocols/secrets/__init__.py +1 -0
- ciris_engine/protocols/services/__init__.py +80 -0
- ciris_engine/protocols/services/adaptation/__init__.py +7 -0
- ciris_engine/protocols/services/adaptation/self_observation.py +265 -0
- ciris_engine/protocols/services/governance/__init__.py +20 -0
- ciris_engine/protocols/services/governance/communication.py +58 -0
- ciris_engine/protocols/services/governance/filter.py +56 -0
- ciris_engine/protocols/services/governance/visibility.py +32 -0
- ciris_engine/protocols/services/governance/wa_auth.py +192 -0
- ciris_engine/protocols/services/governance/wise_authority.py +75 -0
- ciris_engine/protocols/services/graph/__init__.py +19 -0
- ciris_engine/protocols/services/graph/audit.py +92 -0
- ciris_engine/protocols/services/graph/config.py +54 -0
- ciris_engine/protocols/services/graph/incident_management.py +103 -0
- ciris_engine/protocols/services/graph/memory.py +110 -0
- ciris_engine/protocols/services/graph/telemetry.py +51 -0
- ciris_engine/protocols/services/graph/tsdb_consolidation.py +87 -0
- ciris_engine/protocols/services/infrastructure/__init__.py +11 -0
- ciris_engine/protocols/services/infrastructure/authentication.py +159 -0
- ciris_engine/protocols/services/infrastructure/credit_gate.py +46 -0
- ciris_engine/protocols/services/infrastructure/database_maintenance.py +25 -0
- ciris_engine/protocols/services/infrastructure/resource_monitor.py +83 -0
- ciris_engine/protocols/services/lifecycle/__init__.py +13 -0
- ciris_engine/protocols/services/lifecycle/initialization.py +41 -0
- ciris_engine/protocols/services/lifecycle/scheduler.py +42 -0
- ciris_engine/protocols/services/lifecycle/shutdown.py +50 -0
- ciris_engine/protocols/services/lifecycle/time.py +31 -0
- ciris_engine/protocols/services/runtime/__init__.py +13 -0
- ciris_engine/protocols/services/runtime/llm.py +50 -0
- ciris_engine/protocols/services/runtime/runtime_control.py +193 -0
- ciris_engine/protocols/services/runtime/secrets.py +100 -0
- ciris_engine/protocols/services/runtime/tool.py +123 -0
- ciris_engine/protocols/telemetry/__init__.py +1 -0
- ciris_engine/protocols/utils/__init__.py +1 -0
- ciris_engine/schemas/__init__.py +112 -0
- ciris_engine/schemas/actions/__init__.py +37 -0
- ciris_engine/schemas/actions/parameters.py +137 -0
- ciris_engine/schemas/adapters/__init__.py +13 -0
- ciris_engine/schemas/adapters/cirisnode.py +135 -0
- ciris_engine/schemas/adapters/cli.py +97 -0
- ciris_engine/schemas/adapters/cli_tools.py +98 -0
- ciris_engine/schemas/adapters/discord.py +125 -0
- ciris_engine/schemas/adapters/graphql_core.py +144 -0
- ciris_engine/schemas/adapters/registration.py +47 -0
- ciris_engine/schemas/adapters/runtime_context.py +48 -0
- ciris_engine/schemas/adapters/tool_execution.py +45 -0
- ciris_engine/schemas/adapters/tools.py +96 -0
- ciris_engine/schemas/api/__init__.py +1 -0
- ciris_engine/schemas/api/agent.py +50 -0
- ciris_engine/schemas/api/audit.py +38 -0
- ciris_engine/schemas/api/auth.py +351 -0
- ciris_engine/schemas/api/config_security.py +242 -0
- ciris_engine/schemas/api/emergency.py +111 -0
- ciris_engine/schemas/api/responses.py +72 -0
- ciris_engine/schemas/api/runtime.py +26 -0
- ciris_engine/schemas/api/telemetry.py +109 -0
- ciris_engine/schemas/api/wa.py +90 -0
- ciris_engine/schemas/audit/__init__.py +13 -0
- ciris_engine/schemas/audit/core.py +139 -0
- ciris_engine/schemas/audit/hash_chain.py +58 -0
- ciris_engine/schemas/audit/verification.py +131 -0
- ciris_engine/schemas/buses/__init__.py +1 -0
- ciris_engine/schemas/config/__init__.py +41 -0
- ciris_engine/schemas/config/agent.py +279 -0
- ciris_engine/schemas/config/cognitive_state_behaviors.py +194 -0
- ciris_engine/schemas/config/default_dsar_sops.py +178 -0
- ciris_engine/schemas/config/essential.py +195 -0
- ciris_engine/schemas/config/tickets.py +86 -0
- ciris_engine/schemas/conscience/__init__.py +25 -0
- ciris_engine/schemas/conscience/context.py +34 -0
- ciris_engine/schemas/conscience/core.py +145 -0
- ciris_engine/schemas/conscience/results.py +24 -0
- ciris_engine/schemas/consent/__init__.py +5 -0
- ciris_engine/schemas/consent/core.py +404 -0
- ciris_engine/schemas/context/__init__.py +1 -0
- ciris_engine/schemas/covenant.py +382 -0
- ciris_engine/schemas/data/__init__.py +1 -0
- ciris_engine/schemas/dma/__init__.py +16 -0
- ciris_engine/schemas/dma/core.py +199 -0
- ciris_engine/schemas/dma/faculty.py +192 -0
- ciris_engine/schemas/dma/prompts.py +172 -0
- ciris_engine/schemas/dma/results.py +103 -0
- ciris_engine/schemas/formatters/__init__.py +1 -0
- ciris_engine/schemas/handlers/__init__.py +10 -0
- ciris_engine/schemas/handlers/context.py +119 -0
- ciris_engine/schemas/handlers/contexts.py +100 -0
- ciris_engine/schemas/handlers/core.py +167 -0
- ciris_engine/schemas/handlers/memory_schemas.py +67 -0
- ciris_engine/schemas/handlers/schemas.py +95 -0
- ciris_engine/schemas/identity.py +149 -0
- ciris_engine/schemas/infrastructure/__init__.py +1 -0
- ciris_engine/schemas/infrastructure/base.py +256 -0
- ciris_engine/schemas/infrastructure/behavioral_patterns.py +129 -0
- ciris_engine/schemas/infrastructure/feedback_loop.py +57 -0
- ciris_engine/schemas/infrastructure/identity_variance.py +141 -0
- ciris_engine/schemas/infrastructure/oauth.py +175 -0
- ciris_engine/schemas/infrastructure/wa_cli_wizard.py +54 -0
- ciris_engine/schemas/persistence/__init__.py +34 -0
- ciris_engine/schemas/persistence/core.py +140 -0
- ciris_engine/schemas/persistence/correlations.py +73 -0
- ciris_engine/schemas/persistence/postgres/__init__.py +1 -0
- ciris_engine/schemas/persistence/postgres/tables.py +280 -0
- ciris_engine/schemas/persistence/sqlite/__init__.py +1 -0
- ciris_engine/schemas/persistence/sqlite/tables.py +281 -0
- ciris_engine/schemas/platform.py +149 -0
- ciris_engine/schemas/processors/__init__.py +26 -0
- ciris_engine/schemas/processors/base.py +130 -0
- ciris_engine/schemas/processors/cognitive.py +77 -0
- ciris_engine/schemas/processors/context.py +35 -0
- ciris_engine/schemas/processors/core.py +152 -0
- ciris_engine/schemas/processors/dma.py +105 -0
- ciris_engine/schemas/processors/error.py +122 -0
- ciris_engine/schemas/processors/main.py +109 -0
- ciris_engine/schemas/processors/phase_results.py +21 -0
- ciris_engine/schemas/processors/results.py +99 -0
- ciris_engine/schemas/processors/solitude.py +79 -0
- ciris_engine/schemas/processors/state.py +202 -0
- ciris_engine/schemas/processors/state_example.py +177 -0
- ciris_engine/schemas/processors/states.py +21 -0
- ciris_engine/schemas/processors/status.py +34 -0
- ciris_engine/schemas/registries/__init__.py +1 -0
- ciris_engine/schemas/registries/base.py +66 -0
- ciris_engine/schemas/resources/__init__.py +15 -0
- ciris_engine/schemas/resources/crisis.py +315 -0
- ciris_engine/schemas/runtime/__init__.py +42 -0
- ciris_engine/schemas/runtime/adapter_management.py +186 -0
- ciris_engine/schemas/runtime/api.py +58 -0
- ciris_engine/schemas/runtime/audit.py +50 -0
- ciris_engine/schemas/runtime/bootstrap.py +33 -0
- ciris_engine/schemas/runtime/contexts.py +61 -0
- ciris_engine/schemas/runtime/core.py +161 -0
- ciris_engine/schemas/runtime/enums.py +167 -0
- ciris_engine/schemas/runtime/extended.py +232 -0
- ciris_engine/schemas/runtime/manifest.py +311 -0
- ciris_engine/schemas/runtime/memory.py +60 -0
- ciris_engine/schemas/runtime/messages.py +108 -0
- ciris_engine/schemas/runtime/models.py +156 -0
- ciris_engine/schemas/runtime/processing_context.py +43 -0
- ciris_engine/schemas/runtime/protocols_core.py +96 -0
- ciris_engine/schemas/runtime/resources.py +33 -0
- ciris_engine/schemas/runtime/system_context.py +417 -0
- ciris_engine/schemas/secrets/__init__.py +1 -0
- ciris_engine/schemas/secrets/core.py +267 -0
- ciris_engine/schemas/secrets/service.py +95 -0
- ciris_engine/schemas/services/__init__.py +33 -0
- ciris_engine/schemas/services/audit_summary_node.py +172 -0
- ciris_engine/schemas/services/authority/__init__.py +39 -0
- ciris_engine/schemas/services/authority/jwt.py +158 -0
- ciris_engine/schemas/services/authority/wa_updates.py +138 -0
- ciris_engine/schemas/services/authority/wise_authority.py +163 -0
- ciris_engine/schemas/services/authority_core.py +370 -0
- ciris_engine/schemas/services/capabilities.py +72 -0
- ciris_engine/schemas/services/community_core.py +95 -0
- ciris_engine/schemas/services/context.py +111 -0
- ciris_engine/schemas/services/conversation_summary_node.py +189 -0
- ciris_engine/schemas/services/core/__init__.py +153 -0
- ciris_engine/schemas/services/core/runtime.py +262 -0
- ciris_engine/schemas/services/core/runtime_config.py +117 -0
- ciris_engine/schemas/services/core/secrets.py +65 -0
- ciris_engine/schemas/services/correlation_node.py +179 -0
- ciris_engine/schemas/services/credit_gate.py +92 -0
- ciris_engine/schemas/services/discord_nodes.py +299 -0
- ciris_engine/schemas/services/feedback_core.py +131 -0
- ciris_engine/schemas/services/filters_core.py +270 -0
- ciris_engine/schemas/services/governance.py +26 -0
- ciris_engine/schemas/services/graph/__init__.py +26 -0
- ciris_engine/schemas/services/graph/attributes.py +254 -0
- ciris_engine/schemas/services/graph/audit.py +98 -0
- ciris_engine/schemas/services/graph/consolidation.py +338 -0
- ciris_engine/schemas/services/graph/edge_types.py +43 -0
- ciris_engine/schemas/services/graph/edges.py +88 -0
- ciris_engine/schemas/services/graph/incident.py +312 -0
- ciris_engine/schemas/services/graph/memory.py +84 -0
- ciris_engine/schemas/services/graph/node_data.py +174 -0
- ciris_engine/schemas/services/graph/query_results.py +82 -0
- ciris_engine/schemas/services/graph/telemetry.py +250 -0
- ciris_engine/schemas/services/graph/tsdb_consolidation.py +27 -0
- ciris_engine/schemas/services/graph/tsdb_models.py +107 -0
- ciris_engine/schemas/services/graph_core.py +196 -0
- ciris_engine/schemas/services/graph_typed_nodes.py +194 -0
- ciris_engine/schemas/services/infrastructure/__init__.py +1 -0
- ciris_engine/schemas/services/infrastructure/resource_monitor.py +20 -0
- ciris_engine/schemas/services/lifecycle/__init__.py +9 -0
- ciris_engine/schemas/services/lifecycle/initialization.py +33 -0
- ciris_engine/schemas/services/lifecycle/time.py +50 -0
- ciris_engine/schemas/services/llm.py +187 -0
- ciris_engine/schemas/services/metadata.py +43 -0
- ciris_engine/schemas/services/nodes.py +704 -0
- ciris_engine/schemas/services/operations.py +126 -0
- ciris_engine/schemas/services/requests.py +128 -0
- ciris_engine/schemas/services/resources_core.py +182 -0
- ciris_engine/schemas/services/runtime_control.py +1010 -0
- ciris_engine/schemas/services/shutdown.py +88 -0
- ciris_engine/schemas/services/special/__init__.py +0 -0
- ciris_engine/schemas/services/special/self_observation.py +396 -0
- ciris_engine/schemas/services/trace_summary_node.py +199 -0
- ciris_engine/schemas/services/visibility.py +98 -0
- ciris_engine/schemas/streaming/__init__.py +10 -0
- ciris_engine/schemas/streaming/reasoning_stream.py +95 -0
- ciris_engine/schemas/telemetry/__init__.py +0 -0
- ciris_engine/schemas/telemetry/collector.py +67 -0
- ciris_engine/schemas/telemetry/core.py +252 -0
- ciris_engine/schemas/telemetry/unified.py +59 -0
- ciris_engine/schemas/tools.py +72 -0
- ciris_engine/schemas/types.py +47 -0
- ciris_engine/schemas/utils/__init__.py +1 -0
- ciris_engine/schemas/utils/config_validator.py +54 -0
- ciris_engine/utils/__init__.py +1 -0
- ciris_engine/utils/serialization.py +35 -0
- ciris_sdk/__init__.py +124 -0
- ciris_sdk/auth_store.py +261 -0
- ciris_sdk/client.py +261 -0
- ciris_sdk/exceptions.py +73 -0
- ciris_sdk/model_types.py +258 -0
- ciris_sdk/models.py +354 -0
- ciris_sdk/pagination.py +214 -0
- ciris_sdk/rate_limiter.py +188 -0
- ciris_sdk/setup.py +17 -0
- ciris_sdk/telemetry_models.py +257 -0
- ciris_sdk/telemetry_responses.py +199 -0
- ciris_sdk/transport.py +177 -0
- ciris_sdk/websocket.py +400 -0
- 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
|