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,1120 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
from datetime import datetime, timedelta, timezone
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
|
|
7
|
+
from uuid import uuid4
|
|
8
|
+
|
|
9
|
+
from ciris_engine.constants import UTC_TIMEZONE_SUFFIX
|
|
10
|
+
from ciris_engine.logic.config import get_sqlite_db_full_path
|
|
11
|
+
from ciris_engine.logic.persistence import get_db_connection, initialize_database
|
|
12
|
+
from ciris_engine.logic.secrets.service import SecretsService
|
|
13
|
+
from ciris_engine.logic.services.base_graph_service import BaseGraphService, GraphNodeConvertible
|
|
14
|
+
from ciris_engine.logic.utils.jsondict_helpers import get_dict, get_list, get_str
|
|
15
|
+
from ciris_engine.protocols.services import GraphMemoryServiceProtocol, MemoryService
|
|
16
|
+
from ciris_engine.protocols.services.lifecycle.time import TimeServiceProtocol
|
|
17
|
+
from ciris_engine.schemas.runtime.enums import ServiceType
|
|
18
|
+
from ciris_engine.schemas.runtime.memory import TimeSeriesDataPoint
|
|
19
|
+
from ciris_engine.schemas.secrets.service import DecapsulationContext
|
|
20
|
+
from ciris_engine.schemas.services.graph.attributes import AnyNodeAttributes, LogNodeAttributes, TelemetryNodeAttributes
|
|
21
|
+
from ciris_engine.schemas.services.graph.memory import MemorySearchFilter
|
|
22
|
+
from ciris_engine.schemas.services.graph_core import GraphEdge, GraphNode, GraphNodeAttributes, GraphScope, NodeType
|
|
23
|
+
from ciris_engine.schemas.services.operations import MemoryOpResult, MemoryOpStatus, MemoryQuery
|
|
24
|
+
from ciris_engine.schemas.types import JSONDict, JSONList, JSONValue
|
|
25
|
+
|
|
26
|
+
# No longer using psutil - resource_monitor handles process metrics
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class DateTimeEncoder(json.JSONEncoder):
|
|
33
|
+
"""Custom JSON encoder that handles datetime objects and Pydantic models."""
|
|
34
|
+
|
|
35
|
+
def default(self, obj: object) -> Union[str, JSONDict, JSONList, int, float, bool, None]:
|
|
36
|
+
if isinstance(obj, datetime):
|
|
37
|
+
return obj.isoformat()
|
|
38
|
+
# Handle Pydantic models
|
|
39
|
+
if hasattr(obj, "model_dump"):
|
|
40
|
+
return obj.model_dump() # type: ignore[no-any-return]
|
|
41
|
+
# Handle any object with to_dict method
|
|
42
|
+
if hasattr(obj, "to_dict"):
|
|
43
|
+
return obj.to_dict() # type: ignore[no-any-return]
|
|
44
|
+
return super().default(obj) # type: ignore[no-any-return]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class LocalGraphMemoryService(BaseGraphService, MemoryService, GraphMemoryServiceProtocol):
|
|
48
|
+
"""Graph memory backed by the persistence database."""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
db_path: Optional[str] = None,
|
|
53
|
+
secrets_service: Optional[SecretsService] = None,
|
|
54
|
+
time_service: Optional[TimeServiceProtocol] = None,
|
|
55
|
+
) -> None:
|
|
56
|
+
# Initialize BaseGraphService - LocalGraphMemoryService doesn't use memory_bus
|
|
57
|
+
super().__init__(memory_bus=None, time_service=time_service)
|
|
58
|
+
|
|
59
|
+
import logging
|
|
60
|
+
|
|
61
|
+
logger_temp = logging.getLogger(__name__)
|
|
62
|
+
logger_temp.debug(f"LocalGraphMemoryService.__init__ - received db_path: {db_path!r}")
|
|
63
|
+
|
|
64
|
+
self.db_path = db_path or get_sqlite_db_full_path()
|
|
65
|
+
logger_temp.debug(f"LocalGraphMemoryService.__init__ - self.db_path set to: {self.db_path!r}")
|
|
66
|
+
|
|
67
|
+
initialize_database(db_path=self.db_path)
|
|
68
|
+
self.secrets_service = secrets_service # Must be provided, not created here
|
|
69
|
+
self._start_time: Optional[datetime] = None
|
|
70
|
+
|
|
71
|
+
async def memorize(self, node: GraphNode) -> "MemoryOpResult[GraphNode]":
|
|
72
|
+
"""Store a node with automatic secrets detection and processing."""
|
|
73
|
+
self._track_request()
|
|
74
|
+
try:
|
|
75
|
+
# Process secrets in node attributes before storing
|
|
76
|
+
processed_node = await self._process_secrets_for_memorize(node)
|
|
77
|
+
|
|
78
|
+
from ciris_engine.logic.persistence.models import graph as persistence
|
|
79
|
+
|
|
80
|
+
if self._time_service:
|
|
81
|
+
persistence.add_graph_node(processed_node, db_path=self.db_path, time_service=self._time_service)
|
|
82
|
+
else:
|
|
83
|
+
raise RuntimeError("TimeService is required for adding graph nodes")
|
|
84
|
+
return MemoryOpResult[GraphNode](status=MemoryOpStatus.OK, data=processed_node)
|
|
85
|
+
except Exception as e:
|
|
86
|
+
logger.exception("Error storing node %s: %s", node.id, e)
|
|
87
|
+
return MemoryOpResult[GraphNode](status=MemoryOpStatus.DENIED, error=str(e))
|
|
88
|
+
|
|
89
|
+
async def recall(self, recall_query: MemoryQuery) -> List[GraphNode]:
|
|
90
|
+
"""Recall nodes from memory based on query."""
|
|
91
|
+
self._track_request()
|
|
92
|
+
try:
|
|
93
|
+
from ciris_engine.logic.persistence import get_all_graph_nodes
|
|
94
|
+
from ciris_engine.logic.persistence.models import graph as persistence
|
|
95
|
+
|
|
96
|
+
logger.debug(
|
|
97
|
+
f"Memory recall called with node_id='{recall_query.node_id}', scope={recall_query.scope}, type={recall_query.type}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Check if this is a wildcard query
|
|
101
|
+
if recall_query.node_id in ["*", "%", "all"]:
|
|
102
|
+
return await self._recall_wildcard(recall_query)
|
|
103
|
+
else:
|
|
104
|
+
return await self._recall_single_node(recall_query)
|
|
105
|
+
|
|
106
|
+
except Exception as e:
|
|
107
|
+
logger.exception("Error recalling nodes for query %s: %s", recall_query.node_id, e)
|
|
108
|
+
return []
|
|
109
|
+
|
|
110
|
+
async def _recall_wildcard(self, recall_query: MemoryQuery) -> List[GraphNode]:
|
|
111
|
+
"""Handle wildcard recall queries."""
|
|
112
|
+
from ciris_engine.logic.persistence import get_all_graph_nodes
|
|
113
|
+
|
|
114
|
+
logger.debug(f"Memory recall: wildcard query with scope {recall_query.scope}, type {recall_query.type}")
|
|
115
|
+
|
|
116
|
+
# Use the new get_all_graph_nodes function
|
|
117
|
+
nodes = get_all_graph_nodes(
|
|
118
|
+
scope=recall_query.scope,
|
|
119
|
+
node_type=recall_query.type.value if recall_query.type else None,
|
|
120
|
+
limit=100, # Reasonable default limit for wildcard queries
|
|
121
|
+
db_path=self.db_path,
|
|
122
|
+
)
|
|
123
|
+
logger.debug(f"Wildcard query returned {len(nodes)} nodes")
|
|
124
|
+
|
|
125
|
+
# Process secrets and edges for all nodes
|
|
126
|
+
processed_nodes = []
|
|
127
|
+
for node in nodes:
|
|
128
|
+
processed_node = await self._process_node_for_recall(node, recall_query.include_edges)
|
|
129
|
+
processed_nodes.append(processed_node)
|
|
130
|
+
|
|
131
|
+
return processed_nodes
|
|
132
|
+
|
|
133
|
+
async def _recall_single_node(self, recall_query: MemoryQuery) -> List[GraphNode]:
|
|
134
|
+
"""Handle single node recall queries."""
|
|
135
|
+
from ciris_engine.logic.persistence.models import graph as persistence
|
|
136
|
+
|
|
137
|
+
logger.debug(f"Memory recall: getting node {recall_query.node_id} scope {recall_query.scope}")
|
|
138
|
+
stored = persistence.get_graph_node(recall_query.node_id, recall_query.scope, db_path=self.db_path)
|
|
139
|
+
if not stored:
|
|
140
|
+
return []
|
|
141
|
+
|
|
142
|
+
# Process secrets in the node's attributes
|
|
143
|
+
if stored.attributes:
|
|
144
|
+
processed_attrs = await self._process_secrets_for_recall(stored.attributes, "recall")
|
|
145
|
+
stored = GraphNode(
|
|
146
|
+
id=stored.id,
|
|
147
|
+
type=stored.type,
|
|
148
|
+
scope=stored.scope,
|
|
149
|
+
attributes=processed_attrs,
|
|
150
|
+
version=stored.version,
|
|
151
|
+
updated_by=stored.updated_by,
|
|
152
|
+
updated_at=stored.updated_at,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
# Handle edges if requested
|
|
156
|
+
if recall_query.include_edges and recall_query.depth > 0:
|
|
157
|
+
stored = await self._process_node_with_edges(stored, include_edges=True)
|
|
158
|
+
|
|
159
|
+
# If depth > 1, fetch connected nodes recursively
|
|
160
|
+
if recall_query.depth > 1:
|
|
161
|
+
return await self._fetch_connected_nodes(stored, recall_query.depth)
|
|
162
|
+
|
|
163
|
+
return [stored]
|
|
164
|
+
|
|
165
|
+
async def _process_node_for_recall(self, node: GraphNode, include_edges: bool) -> GraphNode:
|
|
166
|
+
"""Process a single node for recall, handling secrets and edges."""
|
|
167
|
+
# Process attributes - always returns dict for compatibility
|
|
168
|
+
processed_attrs: JSONDict = {}
|
|
169
|
+
if node.attributes:
|
|
170
|
+
processed_attrs = await self._process_secrets_for_recall(node.attributes, "recall")
|
|
171
|
+
|
|
172
|
+
# Create node with processed attributes
|
|
173
|
+
processed_node = GraphNode(
|
|
174
|
+
id=node.id,
|
|
175
|
+
type=node.type,
|
|
176
|
+
scope=node.scope,
|
|
177
|
+
attributes=processed_attrs,
|
|
178
|
+
version=node.version,
|
|
179
|
+
updated_by=node.updated_by,
|
|
180
|
+
updated_at=node.updated_at,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# Include edges if requested
|
|
184
|
+
if include_edges:
|
|
185
|
+
processed_node = await self._process_node_with_edges(processed_node, include_edges=True)
|
|
186
|
+
|
|
187
|
+
return processed_node
|
|
188
|
+
|
|
189
|
+
async def forget(self, node: GraphNode) -> "MemoryOpResult[GraphNode]":
|
|
190
|
+
"""Forget a node and clean up any associated secrets."""
|
|
191
|
+
self._track_request()
|
|
192
|
+
try:
|
|
193
|
+
# First retrieve the node to check for secrets
|
|
194
|
+
from ciris_engine.logic.persistence.models import graph as persistence
|
|
195
|
+
|
|
196
|
+
stored = persistence.get_graph_node(node.id, node.scope, db_path=self.db_path)
|
|
197
|
+
if stored:
|
|
198
|
+
self._process_secrets_for_forget(stored.attributes)
|
|
199
|
+
|
|
200
|
+
from ciris_engine.logic.persistence.models import graph as persistence
|
|
201
|
+
|
|
202
|
+
persistence.delete_graph_node(node.id, node.scope, db_path=self.db_path)
|
|
203
|
+
return MemoryOpResult[GraphNode](status=MemoryOpStatus.OK, data=node)
|
|
204
|
+
except Exception as e:
|
|
205
|
+
logger.exception("Error forgetting node %s: %s", node.id, e)
|
|
206
|
+
return MemoryOpResult[GraphNode](status=MemoryOpStatus.DENIED, error=str(e))
|
|
207
|
+
|
|
208
|
+
async def export_identity_context(self) -> str:
|
|
209
|
+
"""
|
|
210
|
+
Export agent identity context as formatted text.
|
|
211
|
+
|
|
212
|
+
Uses format_agent_identity() to convert raw graph node data into
|
|
213
|
+
human-readable text with shutdown history.
|
|
214
|
+
"""
|
|
215
|
+
import asyncio
|
|
216
|
+
|
|
217
|
+
from ciris_engine.logic.formatters.identity import format_agent_identity
|
|
218
|
+
|
|
219
|
+
def _query_identity() -> str:
|
|
220
|
+
with get_db_connection(db_path=self.db_path) as conn:
|
|
221
|
+
cursor = conn.cursor()
|
|
222
|
+
cursor.execute(
|
|
223
|
+
"SELECT node_id, attributes_json FROM graph_nodes WHERE scope = ?", (GraphScope.IDENTITY.value,)
|
|
224
|
+
)
|
|
225
|
+
rows = cursor.fetchall()
|
|
226
|
+
|
|
227
|
+
# If we have identity nodes, format the first one
|
|
228
|
+
# (typically there's only one identity node per agent)
|
|
229
|
+
if rows:
|
|
230
|
+
# Handle PostgreSQL JSONB vs SQLite TEXT
|
|
231
|
+
attrs_json = rows[0]["attributes_json"]
|
|
232
|
+
if attrs_json:
|
|
233
|
+
attrs = attrs_json if isinstance(attrs_json, dict) else json.loads(attrs_json)
|
|
234
|
+
else:
|
|
235
|
+
attrs = {}
|
|
236
|
+
return format_agent_identity(attrs)
|
|
237
|
+
|
|
238
|
+
return ""
|
|
239
|
+
|
|
240
|
+
loop = asyncio.get_event_loop()
|
|
241
|
+
return await loop.run_in_executor(None, _query_identity)
|
|
242
|
+
|
|
243
|
+
async def _process_secrets_for_memorize(self, node: GraphNode) -> GraphNode:
|
|
244
|
+
"""Process secrets in node attributes during memorization."""
|
|
245
|
+
if not node.attributes:
|
|
246
|
+
return node
|
|
247
|
+
|
|
248
|
+
# Convert attributes to JSON string for processing
|
|
249
|
+
# Handle both dict and Pydantic model attributes
|
|
250
|
+
if hasattr(node.attributes, "model_dump"):
|
|
251
|
+
attributes_dict = node.attributes.model_dump()
|
|
252
|
+
else:
|
|
253
|
+
attributes_dict = node.attributes
|
|
254
|
+
attributes_str = json.dumps(attributes_dict, cls=DateTimeEncoder)
|
|
255
|
+
|
|
256
|
+
# Process for secrets detection and replacement
|
|
257
|
+
# SecretsService requires source_message_id
|
|
258
|
+
if not self.secrets_service:
|
|
259
|
+
logger.warning(
|
|
260
|
+
f"Secrets service unavailable for memorize operation on node {node.id}. "
|
|
261
|
+
f"Secrets will NOT be encrypted. This may expose sensitive data."
|
|
262
|
+
)
|
|
263
|
+
return node
|
|
264
|
+
processed_text, secret_refs = await self.secrets_service.process_incoming_text(
|
|
265
|
+
attributes_str, source_message_id=f"memorize_{node.id}"
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# Create new node with processed attributes
|
|
269
|
+
processed_attributes = json.loads(processed_text) if processed_text != attributes_str else node.attributes
|
|
270
|
+
|
|
271
|
+
# Add secret references to node metadata if any were found
|
|
272
|
+
if secret_refs:
|
|
273
|
+
if isinstance(processed_attributes, dict):
|
|
274
|
+
refs_list = get_list(processed_attributes, "secret_refs", [])
|
|
275
|
+
refs_list.extend([ref.uuid for ref in secret_refs])
|
|
276
|
+
processed_attributes["secret_refs"] = refs_list
|
|
277
|
+
logger.info(f"Stored {len(secret_refs)} secret references in memory node {node.id}")
|
|
278
|
+
|
|
279
|
+
return GraphNode(
|
|
280
|
+
id=node.id,
|
|
281
|
+
type=node.type,
|
|
282
|
+
scope=node.scope,
|
|
283
|
+
attributes=processed_attributes,
|
|
284
|
+
version=node.version,
|
|
285
|
+
updated_by=node.updated_by,
|
|
286
|
+
updated_at=node.updated_at,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
async def _process_secrets_for_recall(
|
|
290
|
+
self, attributes: AnyNodeAttributes | GraphNodeAttributes | JSONDict, action_type: str
|
|
291
|
+
) -> JSONDict:
|
|
292
|
+
"""Process secrets in recalled attributes for potential decryption."""
|
|
293
|
+
if not attributes:
|
|
294
|
+
return {}
|
|
295
|
+
|
|
296
|
+
# Convert GraphNodeAttributes to dict if needed
|
|
297
|
+
attributes_dict: JSONDict
|
|
298
|
+
if hasattr(attributes, "model_dump"):
|
|
299
|
+
attributes_dict = attributes.model_dump()
|
|
300
|
+
else: # isinstance(attributes, dict)
|
|
301
|
+
attributes_dict = attributes
|
|
302
|
+
|
|
303
|
+
secret_refs = attributes_dict.get("secret_refs", [])
|
|
304
|
+
if not secret_refs:
|
|
305
|
+
return attributes_dict
|
|
306
|
+
|
|
307
|
+
should_decrypt = False
|
|
308
|
+
if self.secrets_service and hasattr(self.secrets_service, "filter"):
|
|
309
|
+
should_decrypt = action_type in getattr(
|
|
310
|
+
self.secrets_service.filter.detection_config, "auto_decrypt_for_actions", ["speak", "tool"]
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
if should_decrypt:
|
|
314
|
+
_attributes_str = json.dumps(attributes_dict, cls=DateTimeEncoder)
|
|
315
|
+
|
|
316
|
+
if not self.secrets_service:
|
|
317
|
+
logger.warning(
|
|
318
|
+
f"Secrets service unavailable for recall operation. "
|
|
319
|
+
f"Secrets will NOT be decrypted for action_type={action_type}. "
|
|
320
|
+
f"This may prevent proper secret handling."
|
|
321
|
+
)
|
|
322
|
+
return attributes_dict
|
|
323
|
+
decapsulated_attributes = await self.secrets_service.decapsulate_secrets_in_parameters(
|
|
324
|
+
action_type=action_type,
|
|
325
|
+
action_params=attributes_dict,
|
|
326
|
+
context=DecapsulationContext(action_type=action_type, thought_id="memory_recall", user_id="system"),
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
if decapsulated_attributes != attributes_dict:
|
|
330
|
+
logger.info(f"Auto-decrypted secrets in recalled data for {action_type}")
|
|
331
|
+
# Type assertion: decapsulate_secrets_in_parameters should return dict
|
|
332
|
+
assert isinstance(decapsulated_attributes, dict)
|
|
333
|
+
return decapsulated_attributes
|
|
334
|
+
|
|
335
|
+
return attributes_dict
|
|
336
|
+
|
|
337
|
+
def _process_secrets_for_forget(self, attributes: AnyNodeAttributes | GraphNodeAttributes | JSONDict) -> None:
|
|
338
|
+
"""Clean up secrets when forgetting a node."""
|
|
339
|
+
if not attributes:
|
|
340
|
+
return
|
|
341
|
+
|
|
342
|
+
# Convert GraphNodeAttributes to dict if needed
|
|
343
|
+
attributes_dict: JSONDict
|
|
344
|
+
if hasattr(attributes, "model_dump"):
|
|
345
|
+
attributes_dict = attributes.model_dump()
|
|
346
|
+
else: # isinstance(attributes, dict)
|
|
347
|
+
attributes_dict = attributes
|
|
348
|
+
|
|
349
|
+
# Check for secret references
|
|
350
|
+
secret_refs = attributes_dict.get("secret_refs", [])
|
|
351
|
+
if secret_refs:
|
|
352
|
+
# Note: We don't automatically delete secrets on FORGET since they might be
|
|
353
|
+
# referenced elsewhere. This would need to be a conscious decision by the agent.
|
|
354
|
+
if isinstance(secret_refs, list):
|
|
355
|
+
logger.info(f"Node being forgotten contained {len(secret_refs)} secret references")
|
|
356
|
+
else:
|
|
357
|
+
logger.info("Node being forgotten contained secret references")
|
|
358
|
+
|
|
359
|
+
# Could implement reference counting here in the future if needed
|
|
360
|
+
|
|
361
|
+
async def recall_timeseries(
|
|
362
|
+
self,
|
|
363
|
+
scope: str = "default",
|
|
364
|
+
hours: int = 24,
|
|
365
|
+
correlation_types: Optional[List[str]] = None,
|
|
366
|
+
start_time: Optional[datetime] = None,
|
|
367
|
+
end_time: Optional[datetime] = None,
|
|
368
|
+
) -> List[TimeSeriesDataPoint]:
|
|
369
|
+
"""
|
|
370
|
+
Recall time-series data from TSDB graph nodes.
|
|
371
|
+
|
|
372
|
+
Args:
|
|
373
|
+
scope: The memory scope to search (mapped to TSDB tags)
|
|
374
|
+
hours: Number of hours to look back (ignored if start_time/end_time provided)
|
|
375
|
+
correlation_types: Optional filter by correlation types (for compatibility)
|
|
376
|
+
start_time: Specific start time for the query (overrides hours)
|
|
377
|
+
end_time: Specific end time for the query (defaults to now if not provided)
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
List of time-series data points from graph nodes
|
|
381
|
+
"""
|
|
382
|
+
self._track_request()
|
|
383
|
+
try:
|
|
384
|
+
# Calculate time window
|
|
385
|
+
if not self._time_service:
|
|
386
|
+
raise RuntimeError("TimeService is required for recall_timeseries")
|
|
387
|
+
|
|
388
|
+
# Handle time range parameters
|
|
389
|
+
if start_time and end_time:
|
|
390
|
+
# Use explicit time range
|
|
391
|
+
pass
|
|
392
|
+
elif start_time and not end_time:
|
|
393
|
+
# Start time provided, use now as end
|
|
394
|
+
end_time = self._time_service.now()
|
|
395
|
+
else:
|
|
396
|
+
# Fall back to hours-based calculation (backward compatible)
|
|
397
|
+
end_time = end_time or self._time_service.now()
|
|
398
|
+
start_time = end_time - timedelta(hours=hours)
|
|
399
|
+
|
|
400
|
+
# Query TSDB_DATA nodes directly from graph_nodes table
|
|
401
|
+
data_points: List[TimeSeriesDataPoint] = []
|
|
402
|
+
|
|
403
|
+
# Run database query in thread pool to avoid blocking event loop
|
|
404
|
+
import asyncio
|
|
405
|
+
|
|
406
|
+
loop = asyncio.get_event_loop()
|
|
407
|
+
|
|
408
|
+
def _query_tsdb_nodes() -> List[Any]:
|
|
409
|
+
from ciris_engine.logic.persistence.db.dialect import get_adapter
|
|
410
|
+
|
|
411
|
+
adapter = get_adapter()
|
|
412
|
+
with get_db_connection(db_path=self.db_path) as conn:
|
|
413
|
+
cursor = conn.cursor()
|
|
414
|
+
|
|
415
|
+
# Query for TSDB_DATA nodes in the time range
|
|
416
|
+
# ORDER BY DESC to get most recent metrics first
|
|
417
|
+
# PostgreSQL: created_at is already TIMESTAMP, no conversion needed
|
|
418
|
+
# SQLite: created_at is TEXT, use datetime() for comparison
|
|
419
|
+
if adapter.is_postgresql():
|
|
420
|
+
sql = """
|
|
421
|
+
SELECT node_id, attributes_json, created_at
|
|
422
|
+
FROM graph_nodes
|
|
423
|
+
WHERE node_type = 'tsdb_data'
|
|
424
|
+
AND scope = ?
|
|
425
|
+
AND created_at >= ?
|
|
426
|
+
AND created_at <= ?
|
|
427
|
+
ORDER BY created_at DESC
|
|
428
|
+
LIMIT 1000
|
|
429
|
+
"""
|
|
430
|
+
else:
|
|
431
|
+
sql = """
|
|
432
|
+
SELECT node_id, attributes_json, created_at
|
|
433
|
+
FROM graph_nodes
|
|
434
|
+
WHERE node_type = 'tsdb_data'
|
|
435
|
+
AND scope = ?
|
|
436
|
+
AND datetime(created_at) >= datetime(?)
|
|
437
|
+
AND datetime(created_at) <= datetime(?)
|
|
438
|
+
ORDER BY created_at DESC
|
|
439
|
+
LIMIT 1000
|
|
440
|
+
"""
|
|
441
|
+
|
|
442
|
+
cursor.execute(sql, (scope, start_time.isoformat(), end_time.isoformat()))
|
|
443
|
+
return cursor.fetchall()
|
|
444
|
+
|
|
445
|
+
rows = await loop.run_in_executor(None, _query_tsdb_nodes)
|
|
446
|
+
|
|
447
|
+
for row in rows:
|
|
448
|
+
try:
|
|
449
|
+
# Parse attributes - handle PostgreSQL JSONB vs SQLite TEXT
|
|
450
|
+
attrs_json = row["attributes_json"]
|
|
451
|
+
if attrs_json:
|
|
452
|
+
attrs = attrs_json if isinstance(attrs_json, dict) else json.loads(attrs_json)
|
|
453
|
+
else:
|
|
454
|
+
attrs = {}
|
|
455
|
+
|
|
456
|
+
# Extract metric data
|
|
457
|
+
metric_name = attrs.get("metric_name")
|
|
458
|
+
metric_value = attrs.get("value")
|
|
459
|
+
|
|
460
|
+
if not metric_name or metric_value is None:
|
|
461
|
+
continue
|
|
462
|
+
|
|
463
|
+
# Get timestamp from created_at or attributes
|
|
464
|
+
timestamp_str = attrs.get("created_at", row["created_at"])
|
|
465
|
+
timestamp: datetime
|
|
466
|
+
if isinstance(timestamp_str, str):
|
|
467
|
+
# Handle both timezone-aware and naive timestamps
|
|
468
|
+
if "Z" in timestamp_str:
|
|
469
|
+
timestamp = datetime.fromisoformat(timestamp_str.replace("Z", UTC_TIMEZONE_SUFFIX))
|
|
470
|
+
elif "+" in timestamp_str or "-" in timestamp_str[-6:]:
|
|
471
|
+
timestamp = datetime.fromisoformat(timestamp_str)
|
|
472
|
+
else:
|
|
473
|
+
# Naive timestamp - assume UTC
|
|
474
|
+
timestamp = datetime.fromisoformat(timestamp_str)
|
|
475
|
+
if timestamp.tzinfo is None:
|
|
476
|
+
timestamp = timestamp.replace(tzinfo=timezone.utc)
|
|
477
|
+
else:
|
|
478
|
+
timestamp = timestamp_str if isinstance(timestamp_str, datetime) else datetime.now(timezone.utc)
|
|
479
|
+
# Ensure timezone awareness
|
|
480
|
+
if timestamp.tzinfo is None:
|
|
481
|
+
timestamp = timestamp.replace(tzinfo=timezone.utc)
|
|
482
|
+
|
|
483
|
+
# Get tags - check both 'labels' and 'metric_tags' for backward compatibility
|
|
484
|
+
# Database stores in 'labels', but some older code may use 'metric_tags'
|
|
485
|
+
metric_tags = attrs.get("labels", attrs.get("metric_tags", {}))
|
|
486
|
+
if not isinstance(metric_tags, dict):
|
|
487
|
+
metric_tags = {}
|
|
488
|
+
|
|
489
|
+
# Create data point
|
|
490
|
+
data_point = TimeSeriesDataPoint(
|
|
491
|
+
timestamp=timestamp,
|
|
492
|
+
metric_name=metric_name,
|
|
493
|
+
value=float(metric_value),
|
|
494
|
+
correlation_type="METRIC_DATAPOINT", # Default for metrics
|
|
495
|
+
tags=metric_tags,
|
|
496
|
+
source=attrs.get("created_by", "memory_service"),
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
data_points.append(data_point)
|
|
500
|
+
|
|
501
|
+
except Exception as e:
|
|
502
|
+
logger.warning(f"Error parsing TSDB node {row['node_id']}: {e}")
|
|
503
|
+
continue
|
|
504
|
+
|
|
505
|
+
# Sort by timestamp
|
|
506
|
+
data_points.sort(key=lambda x: x.timestamp)
|
|
507
|
+
|
|
508
|
+
logger.debug(f"Recalled {len(data_points)} time series data points from graph nodes")
|
|
509
|
+
return data_points
|
|
510
|
+
|
|
511
|
+
except Exception as e:
|
|
512
|
+
logger.exception(f"Error recalling timeseries data: {e}")
|
|
513
|
+
return []
|
|
514
|
+
|
|
515
|
+
async def memorize_metric(
|
|
516
|
+
self, metric_name: str, value: float, tags: Optional[Dict[str, str]] = None, scope: str = "local"
|
|
517
|
+
) -> "MemoryOpResult[GraphNode]":
|
|
518
|
+
"""
|
|
519
|
+
Convenience method to memorize a metric as a graph node.
|
|
520
|
+
|
|
521
|
+
Metrics are stored only as TSDB_DATA nodes in the graph, not as correlations,
|
|
522
|
+
to prevent double storage and aggregation issues.
|
|
523
|
+
"""
|
|
524
|
+
self._track_request()
|
|
525
|
+
try:
|
|
526
|
+
# Create a graph node for the metric
|
|
527
|
+
if not self._time_service:
|
|
528
|
+
raise RuntimeError("TimeService is required for memorize_metric")
|
|
529
|
+
now = self._time_service.now()
|
|
530
|
+
# Use microsecond precision to ensure unique IDs
|
|
531
|
+
node_id = f"metric_{metric_name}_{int(now.timestamp() * 1000000)}"
|
|
532
|
+
|
|
533
|
+
# Create typed attributes with metric-specific data
|
|
534
|
+
telemetry_attrs = TelemetryNodeAttributes(
|
|
535
|
+
created_at=now,
|
|
536
|
+
updated_at=now,
|
|
537
|
+
created_by="memory_service",
|
|
538
|
+
tags=["metric", metric_name],
|
|
539
|
+
metric_name=metric_name,
|
|
540
|
+
metric_type="gauge", # Default metric type
|
|
541
|
+
value=value,
|
|
542
|
+
start_time=now,
|
|
543
|
+
end_time=now,
|
|
544
|
+
duration_seconds=0.0,
|
|
545
|
+
sample_count=1,
|
|
546
|
+
labels=tags or {},
|
|
547
|
+
service_name="memory_service",
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
node = GraphNode(
|
|
551
|
+
id=node_id,
|
|
552
|
+
type=NodeType.TSDB_DATA,
|
|
553
|
+
scope=GraphScope(scope),
|
|
554
|
+
attributes=telemetry_attrs, # Pass typed Pydantic model directly
|
|
555
|
+
updated_by="memory_service",
|
|
556
|
+
updated_at=now,
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
# Store in graph memory
|
|
560
|
+
memory_result = await self.memorize(node)
|
|
561
|
+
|
|
562
|
+
# No longer storing metrics as correlations - only as graph nodes
|
|
563
|
+
# This prevents double storage and inflated aggregation issues
|
|
564
|
+
|
|
565
|
+
return memory_result
|
|
566
|
+
|
|
567
|
+
except Exception as e:
|
|
568
|
+
logger.exception(f"Error memorizing metric {metric_name}: {e}")
|
|
569
|
+
return MemoryOpResult[GraphNode](status=MemoryOpStatus.DENIED, error=str(e))
|
|
570
|
+
|
|
571
|
+
async def create_edge(self, edge: GraphEdge) -> "MemoryOpResult[GraphEdge]":
|
|
572
|
+
"""Create an edge between two nodes in the memory graph."""
|
|
573
|
+
self._track_request()
|
|
574
|
+
try:
|
|
575
|
+
from ciris_engine.logic.persistence.models.graph import add_graph_edge
|
|
576
|
+
|
|
577
|
+
edge_id = add_graph_edge(edge, db_path=self.db_path)
|
|
578
|
+
logger.info(f"Created edge {edge_id}: {edge.source} -{edge.relationship}-> {edge.target}")
|
|
579
|
+
|
|
580
|
+
return MemoryOpResult[GraphEdge](status=MemoryOpStatus.OK, data=edge)
|
|
581
|
+
except Exception as e:
|
|
582
|
+
logger.exception(f"Error creating edge: {e}")
|
|
583
|
+
return MemoryOpResult[GraphEdge](status=MemoryOpStatus.DENIED, error=str(e))
|
|
584
|
+
|
|
585
|
+
async def get_node_edges(self, node_id: str, scope: GraphScope) -> List[GraphEdge]:
|
|
586
|
+
"""Get all edges connected to a node."""
|
|
587
|
+
try:
|
|
588
|
+
from ciris_engine.logic.persistence.models.graph import get_edges_for_node
|
|
589
|
+
|
|
590
|
+
edges = get_edges_for_node(node_id, scope, db_path=self.db_path)
|
|
591
|
+
return edges
|
|
592
|
+
except Exception as e:
|
|
593
|
+
logger.exception(f"Error getting edges for node {node_id}: {e}")
|
|
594
|
+
return []
|
|
595
|
+
|
|
596
|
+
async def memorize_log(
|
|
597
|
+
self, log_message: str, log_level: str = "INFO", tags: Optional[Dict[str, str]] = None, scope: str = "local"
|
|
598
|
+
) -> "MemoryOpResult[GraphNode]":
|
|
599
|
+
"""
|
|
600
|
+
Convenience method to memorize a log entry as both a graph node and TSDB correlation.
|
|
601
|
+
"""
|
|
602
|
+
self._track_request()
|
|
603
|
+
try:
|
|
604
|
+
# Import correlation models here to avoid circular imports
|
|
605
|
+
from ciris_engine.logic.persistence.models.correlations import add_correlation
|
|
606
|
+
from ciris_engine.schemas.telemetry.core import (
|
|
607
|
+
CorrelationType,
|
|
608
|
+
ServiceCorrelation,
|
|
609
|
+
ServiceCorrelationStatus,
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
# Create a graph node for the log entry
|
|
613
|
+
if not self._time_service:
|
|
614
|
+
raise RuntimeError("TimeService is required for memorize_log")
|
|
615
|
+
now = self._time_service.now()
|
|
616
|
+
node_id = f"log_{log_level}_{int(now.timestamp())}"
|
|
617
|
+
|
|
618
|
+
# Create typed attributes with log-specific data
|
|
619
|
+
log_attrs = LogNodeAttributes(
|
|
620
|
+
created_at=now,
|
|
621
|
+
updated_at=now,
|
|
622
|
+
created_by="memory_service",
|
|
623
|
+
tags=["log", log_level.lower()],
|
|
624
|
+
log_message=log_message,
|
|
625
|
+
log_level=log_level,
|
|
626
|
+
log_tags=tags or {},
|
|
627
|
+
retention_policy="raw",
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
node = GraphNode(
|
|
631
|
+
id=node_id,
|
|
632
|
+
type=NodeType.TSDB_DATA,
|
|
633
|
+
scope=GraphScope(scope),
|
|
634
|
+
attributes=log_attrs, # Pass typed Pydantic model directly
|
|
635
|
+
updated_by="memory_service",
|
|
636
|
+
updated_at=now,
|
|
637
|
+
)
|
|
638
|
+
|
|
639
|
+
# Store in graph memory
|
|
640
|
+
memory_result = await self.memorize(node)
|
|
641
|
+
|
|
642
|
+
# Also store as TSDB correlation
|
|
643
|
+
correlation = ServiceCorrelation(
|
|
644
|
+
correlation_id=str(uuid4()),
|
|
645
|
+
service_type="memory",
|
|
646
|
+
handler_name="memory_service",
|
|
647
|
+
action_type="memorize_log",
|
|
648
|
+
correlation_type=CorrelationType.LOG_ENTRY,
|
|
649
|
+
timestamp=now,
|
|
650
|
+
created_at=now,
|
|
651
|
+
updated_at=now,
|
|
652
|
+
tags=(
|
|
653
|
+
{**tags, "scope": scope, "message": log_message}
|
|
654
|
+
if tags
|
|
655
|
+
else {"scope": scope, "message": log_message}
|
|
656
|
+
),
|
|
657
|
+
status=ServiceCorrelationStatus.COMPLETED,
|
|
658
|
+
retention_policy="raw",
|
|
659
|
+
request_data=None,
|
|
660
|
+
response_data=None,
|
|
661
|
+
metric_data=None,
|
|
662
|
+
log_data=None,
|
|
663
|
+
trace_context=None,
|
|
664
|
+
ttl_seconds=None,
|
|
665
|
+
parent_correlation_id=None,
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
if self._time_service:
|
|
669
|
+
add_correlation(correlation, db_path=self.db_path, time_service=self._time_service)
|
|
670
|
+
else:
|
|
671
|
+
raise RuntimeError("TimeService is required for add_correlation")
|
|
672
|
+
|
|
673
|
+
return memory_result
|
|
674
|
+
|
|
675
|
+
except Exception as e:
|
|
676
|
+
logger.exception(f"Error memorizing log entry: {e}")
|
|
677
|
+
return MemoryOpResult[GraphNode](status=MemoryOpStatus.DENIED, error=str(e))
|
|
678
|
+
|
|
679
|
+
# ============================================================================
|
|
680
|
+
# GRAPH PROTOCOL METHODS
|
|
681
|
+
# ============================================================================
|
|
682
|
+
|
|
683
|
+
async def search(self, query: str, filters: Optional[MemorySearchFilter] = None) -> List[GraphNode]:
|
|
684
|
+
"""Search memories in the graph."""
|
|
685
|
+
self._track_request()
|
|
686
|
+
logger.debug(f"Memory search START: query='{query}', filters={filters}")
|
|
687
|
+
try:
|
|
688
|
+
# Parse query for search terms and filters
|
|
689
|
+
search_terms, query_node_type, query_scope = self._parse_search_query(query)
|
|
690
|
+
|
|
691
|
+
# Extract filters, preferring query string values
|
|
692
|
+
# Convert filter scope string to GraphScope enum
|
|
693
|
+
filter_scope: Optional[GraphScope] = None
|
|
694
|
+
if filters and hasattr(filters, "scope") and filters.scope:
|
|
695
|
+
try:
|
|
696
|
+
filter_scope = GraphScope(filters.scope)
|
|
697
|
+
except ValueError:
|
|
698
|
+
filter_scope = None
|
|
699
|
+
scope = query_scope or filter_scope or GraphScope.LOCAL
|
|
700
|
+
node_type = query_node_type or (filters.node_type if filters and hasattr(filters, "node_type") else None)
|
|
701
|
+
limit = filters.limit if filters and hasattr(filters, "limit") and filters.limit else 100
|
|
702
|
+
|
|
703
|
+
# Fetch nodes based on type
|
|
704
|
+
nodes = await self._fetch_nodes_for_search(scope, node_type, limit)
|
|
705
|
+
|
|
706
|
+
# Filter by content if search terms exist
|
|
707
|
+
if search_terms:
|
|
708
|
+
nodes = self._filter_nodes_by_content(nodes, search_terms)
|
|
709
|
+
|
|
710
|
+
# Process secrets for all nodes
|
|
711
|
+
return await self._process_nodes_for_search(nodes)
|
|
712
|
+
|
|
713
|
+
except Exception as e:
|
|
714
|
+
logger.exception(f"Error searching graph: {e}")
|
|
715
|
+
return []
|
|
716
|
+
|
|
717
|
+
async def _fetch_nodes_for_search(self, scope: GraphScope, node_type: Optional[str], limit: int) -> List[GraphNode]:
|
|
718
|
+
"""Fetch nodes for search based on scope and type."""
|
|
719
|
+
from ciris_engine.logic.persistence import get_all_graph_nodes, get_nodes_by_type
|
|
720
|
+
|
|
721
|
+
if node_type:
|
|
722
|
+
return get_nodes_by_type(
|
|
723
|
+
node_type=node_type,
|
|
724
|
+
scope=scope if isinstance(scope, GraphScope) else GraphScope.LOCAL,
|
|
725
|
+
limit=limit,
|
|
726
|
+
db_path=self.db_path,
|
|
727
|
+
)
|
|
728
|
+
else:
|
|
729
|
+
return get_all_graph_nodes(
|
|
730
|
+
scope=scope if isinstance(scope, GraphScope) else GraphScope.LOCAL,
|
|
731
|
+
limit=limit,
|
|
732
|
+
db_path=self.db_path,
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
async def _process_nodes_for_search(self, nodes: List[GraphNode]) -> List[GraphNode]:
|
|
736
|
+
"""Process nodes for search, handling secrets."""
|
|
737
|
+
processed_nodes = []
|
|
738
|
+
for node in nodes:
|
|
739
|
+
if node.attributes:
|
|
740
|
+
processed_attrs = await self._process_secrets_for_recall(node.attributes, "search")
|
|
741
|
+
processed_node = GraphNode(
|
|
742
|
+
id=node.id,
|
|
743
|
+
type=node.type,
|
|
744
|
+
scope=node.scope,
|
|
745
|
+
attributes=processed_attrs,
|
|
746
|
+
version=node.version,
|
|
747
|
+
updated_by=node.updated_by,
|
|
748
|
+
updated_at=node.updated_at,
|
|
749
|
+
)
|
|
750
|
+
processed_nodes.append(processed_node)
|
|
751
|
+
else:
|
|
752
|
+
processed_nodes.append(node)
|
|
753
|
+
|
|
754
|
+
return processed_nodes
|
|
755
|
+
|
|
756
|
+
# ============================================================================
|
|
757
|
+
# SERVICE PROTOCOL METHODS
|
|
758
|
+
# ============================================================================
|
|
759
|
+
|
|
760
|
+
async def start(self) -> None:
|
|
761
|
+
"""Start the memory service."""
|
|
762
|
+
await super().start()
|
|
763
|
+
self._initialized = True
|
|
764
|
+
if self._time_service:
|
|
765
|
+
self._start_time = self._time_service.now()
|
|
766
|
+
logger.info("LocalGraphMemoryService started")
|
|
767
|
+
|
|
768
|
+
async def stop(self) -> None:
|
|
769
|
+
"""Stop the memory service."""
|
|
770
|
+
logger.info("LocalGraphMemoryService stopped")
|
|
771
|
+
await super().stop()
|
|
772
|
+
|
|
773
|
+
def _collect_custom_metrics(self) -> Dict[str, float]:
|
|
774
|
+
"""Collect memory-specific metrics from v1.4.3 set."""
|
|
775
|
+
metrics = super()._collect_custom_metrics()
|
|
776
|
+
|
|
777
|
+
# Count graph nodes and edges
|
|
778
|
+
node_count = 0
|
|
779
|
+
edge_count = 0
|
|
780
|
+
storage_size_mb = 0.0
|
|
781
|
+
|
|
782
|
+
try:
|
|
783
|
+
with get_db_connection(db_path=self.db_path) as conn:
|
|
784
|
+
cursor = conn.cursor()
|
|
785
|
+
|
|
786
|
+
# Get node count
|
|
787
|
+
cursor.execute("SELECT COUNT(*) FROM graph_nodes")
|
|
788
|
+
result = cursor.fetchone()
|
|
789
|
+
node_count = result[0] if result else 0
|
|
790
|
+
|
|
791
|
+
# Get edge count
|
|
792
|
+
cursor.execute("SELECT COUNT(*) FROM graph_edges")
|
|
793
|
+
result = cursor.fetchone()
|
|
794
|
+
edge_count = result[0] if result else 0
|
|
795
|
+
|
|
796
|
+
except Exception:
|
|
797
|
+
pass
|
|
798
|
+
|
|
799
|
+
# Get database file size
|
|
800
|
+
try:
|
|
801
|
+
import os
|
|
802
|
+
|
|
803
|
+
if os.path.exists(self.db_path):
|
|
804
|
+
storage_size_mb = os.path.getsize(self.db_path) / (1024 * 1024)
|
|
805
|
+
except (OSError, IOError, ImportError):
|
|
806
|
+
# Ignore file system and import errors when checking storage size
|
|
807
|
+
pass
|
|
808
|
+
|
|
809
|
+
# Calculate uptime in seconds
|
|
810
|
+
uptime_seconds = 0.0
|
|
811
|
+
if self._start_time and self._time_service:
|
|
812
|
+
uptime_delta = self._time_service.now() - self._start_time
|
|
813
|
+
uptime_seconds = uptime_delta.total_seconds()
|
|
814
|
+
|
|
815
|
+
# Return EXACTLY the 5 metrics from v1.4.3 set - no other metrics
|
|
816
|
+
memory_metrics = {
|
|
817
|
+
"memory_nodes_total": float(node_count),
|
|
818
|
+
"memory_edges_total": float(edge_count),
|
|
819
|
+
"memory_operations_total": float(self._request_count),
|
|
820
|
+
"memory_db_size_mb": storage_size_mb,
|
|
821
|
+
"memory_uptime_seconds": uptime_seconds,
|
|
822
|
+
# Add secrets_enabled metric for test compatibility
|
|
823
|
+
"secrets_enabled": 1.0 if self.secrets_service else 0.0,
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
# Update with the exact v1.4.3 memory metrics
|
|
827
|
+
metrics.update(memory_metrics)
|
|
828
|
+
|
|
829
|
+
return metrics
|
|
830
|
+
|
|
831
|
+
async def is_healthy(self) -> bool:
|
|
832
|
+
"""Check if service is healthy."""
|
|
833
|
+
import asyncio
|
|
834
|
+
|
|
835
|
+
# Check if service is started
|
|
836
|
+
if not hasattr(self, "_started") or not self._started:
|
|
837
|
+
return False
|
|
838
|
+
|
|
839
|
+
def _check_database() -> bool:
|
|
840
|
+
try:
|
|
841
|
+
# Try a simple database operation
|
|
842
|
+
with get_db_connection(db_path=self.db_path) as conn:
|
|
843
|
+
cursor = conn.cursor()
|
|
844
|
+
cursor.execute("SELECT COUNT(*) FROM graph_nodes")
|
|
845
|
+
cursor.fetchone()
|
|
846
|
+
return True
|
|
847
|
+
except Exception:
|
|
848
|
+
return False
|
|
849
|
+
|
|
850
|
+
loop = asyncio.get_event_loop()
|
|
851
|
+
return await loop.run_in_executor(None, _check_database)
|
|
852
|
+
|
|
853
|
+
async def store_in_graph(self, node: Union[GraphNode, GraphNodeConvertible]) -> str:
|
|
854
|
+
"""Store a node in the graph."""
|
|
855
|
+
# Convert to GraphNode if needed
|
|
856
|
+
if hasattr(node, "to_graph_node"):
|
|
857
|
+
graph_node = node.to_graph_node()
|
|
858
|
+
else:
|
|
859
|
+
graph_node = node
|
|
860
|
+
|
|
861
|
+
result = await self.memorize(graph_node)
|
|
862
|
+
return graph_node.id if result.status == MemoryOpStatus.OK else ""
|
|
863
|
+
|
|
864
|
+
async def query_graph(self, query: MemoryQuery) -> List[GraphNode]:
|
|
865
|
+
"""Query the graph."""
|
|
866
|
+
return await self.recall(query)
|
|
867
|
+
|
|
868
|
+
def get_node_type(self) -> str:
|
|
869
|
+
"""Get the type of nodes this service manages."""
|
|
870
|
+
return "ALL" # Memory service manages all node types
|
|
871
|
+
|
|
872
|
+
# Required methods for BaseGraphService
|
|
873
|
+
|
|
874
|
+
def get_service_type(self) -> ServiceType:
|
|
875
|
+
"""Get the service type."""
|
|
876
|
+
return ServiceType.MEMORY
|
|
877
|
+
|
|
878
|
+
def _get_actions(self) -> List[str]:
|
|
879
|
+
"""Get the list of actions this service supports."""
|
|
880
|
+
return [
|
|
881
|
+
"memorize",
|
|
882
|
+
"recall",
|
|
883
|
+
"forget",
|
|
884
|
+
"memorize_metric",
|
|
885
|
+
"memorize_log",
|
|
886
|
+
"recall_timeseries",
|
|
887
|
+
"export_identity_context",
|
|
888
|
+
"search",
|
|
889
|
+
"create_edge",
|
|
890
|
+
"get_node_edges",
|
|
891
|
+
]
|
|
892
|
+
|
|
893
|
+
def _check_dependencies(self) -> bool:
|
|
894
|
+
"""Check if all dependencies are satisfied."""
|
|
895
|
+
# Memory service doesn't use memory bus (it IS what memory bus uses)
|
|
896
|
+
# Check for optional dependencies
|
|
897
|
+
return True # Base memory service has no hard dependencies
|
|
898
|
+
|
|
899
|
+
# ============================================================================
|
|
900
|
+
# REFACTORED HELPER METHODS TO REDUCE COMPLEXITY
|
|
901
|
+
# ============================================================================
|
|
902
|
+
|
|
903
|
+
async def _process_node_with_edges(self, node: GraphNode, include_edges: bool = False) -> GraphNode:
|
|
904
|
+
"""Process a node and optionally attach its edges."""
|
|
905
|
+
if not include_edges:
|
|
906
|
+
return node
|
|
907
|
+
|
|
908
|
+
from ciris_engine.logic.persistence.models.graph import get_edges_for_node
|
|
909
|
+
|
|
910
|
+
edges = get_edges_for_node(node.id, node.scope, db_path=self.db_path)
|
|
911
|
+
if not edges:
|
|
912
|
+
return node
|
|
913
|
+
|
|
914
|
+
# Convert edges to dict format
|
|
915
|
+
edges_data = [
|
|
916
|
+
{
|
|
917
|
+
"source": edge.source,
|
|
918
|
+
"target": edge.target,
|
|
919
|
+
"relationship": edge.relationship,
|
|
920
|
+
"weight": edge.weight,
|
|
921
|
+
"attributes": (
|
|
922
|
+
edge.attributes.model_dump() if hasattr(edge.attributes, "model_dump") else edge.attributes
|
|
923
|
+
),
|
|
924
|
+
}
|
|
925
|
+
for edge in edges
|
|
926
|
+
]
|
|
927
|
+
|
|
928
|
+
# Add edges to node attributes
|
|
929
|
+
if isinstance(node.attributes, dict):
|
|
930
|
+
node.attributes["_edges"] = edges_data
|
|
931
|
+
else:
|
|
932
|
+
attrs_dict = self._get_attributes_dict(node.attributes)
|
|
933
|
+
attrs_dict["_edges"] = edges_data
|
|
934
|
+
node = GraphNode(
|
|
935
|
+
id=node.id,
|
|
936
|
+
type=node.type,
|
|
937
|
+
scope=node.scope,
|
|
938
|
+
attributes=attrs_dict,
|
|
939
|
+
version=node.version,
|
|
940
|
+
updated_by=node.updated_by,
|
|
941
|
+
updated_at=node.updated_at,
|
|
942
|
+
)
|
|
943
|
+
|
|
944
|
+
return node
|
|
945
|
+
|
|
946
|
+
async def _fetch_connected_nodes(self, start_node: GraphNode, depth: int) -> List[GraphNode]:
|
|
947
|
+
"""Fetch nodes connected to start_node up to specified depth."""
|
|
948
|
+
if depth <= 0:
|
|
949
|
+
return [start_node]
|
|
950
|
+
|
|
951
|
+
from ciris_engine.logic.persistence.models.graph import get_edges_for_node
|
|
952
|
+
|
|
953
|
+
visited_nodes = {start_node.id}
|
|
954
|
+
nodes_to_process = [(start_node, 0)]
|
|
955
|
+
all_nodes = [start_node]
|
|
956
|
+
|
|
957
|
+
while nodes_to_process:
|
|
958
|
+
current_node, current_depth = nodes_to_process.pop(0)
|
|
959
|
+
|
|
960
|
+
if current_depth >= depth - 1:
|
|
961
|
+
continue
|
|
962
|
+
|
|
963
|
+
# Get edges for current node
|
|
964
|
+
current_edges = get_edges_for_node(current_node.id, current_node.scope, db_path=self.db_path)
|
|
965
|
+
|
|
966
|
+
for edge in current_edges:
|
|
967
|
+
# Process this edge's connected node
|
|
968
|
+
result = await self._process_edge_connection(edge, current_node, visited_nodes, current_depth)
|
|
969
|
+
if result:
|
|
970
|
+
connected_node, should_continue = result
|
|
971
|
+
all_nodes.append(connected_node)
|
|
972
|
+
nodes_to_process.append((connected_node, current_depth + 1))
|
|
973
|
+
|
|
974
|
+
return all_nodes
|
|
975
|
+
|
|
976
|
+
async def _process_edge_connection(
|
|
977
|
+
self, edge: Any, current_node: GraphNode, visited_nodes: set[str], current_depth: int
|
|
978
|
+
) -> Optional[Tuple[GraphNode, bool]]:
|
|
979
|
+
"""Process a single edge connection and return the connected node if valid."""
|
|
980
|
+
from ciris_engine.logic.persistence.models import graph as persistence
|
|
981
|
+
|
|
982
|
+
# Determine the connected node ID
|
|
983
|
+
connected_id = edge.target if edge.source == current_node.id else edge.source
|
|
984
|
+
|
|
985
|
+
if connected_id in visited_nodes:
|
|
986
|
+
return None
|
|
987
|
+
|
|
988
|
+
# Fetch the connected node
|
|
989
|
+
connected_node = persistence.get_graph_node(connected_id, edge.scope, db_path=self.db_path)
|
|
990
|
+
|
|
991
|
+
if not connected_node:
|
|
992
|
+
return None
|
|
993
|
+
|
|
994
|
+
visited_nodes.add(connected_id)
|
|
995
|
+
|
|
996
|
+
# Process secrets if needed
|
|
997
|
+
if connected_node.attributes:
|
|
998
|
+
processed_attrs = await self._process_secrets_for_recall(connected_node.attributes, "recall")
|
|
999
|
+
connected_node = GraphNode(
|
|
1000
|
+
id=connected_node.id,
|
|
1001
|
+
type=connected_node.type,
|
|
1002
|
+
scope=connected_node.scope,
|
|
1003
|
+
attributes=processed_attrs,
|
|
1004
|
+
version=connected_node.version,
|
|
1005
|
+
updated_by=connected_node.updated_by,
|
|
1006
|
+
updated_at=connected_node.updated_at,
|
|
1007
|
+
)
|
|
1008
|
+
|
|
1009
|
+
# Process edges for the connected node
|
|
1010
|
+
connected_node = await self._process_node_with_edges(connected_node, include_edges=True)
|
|
1011
|
+
|
|
1012
|
+
return connected_node, True
|
|
1013
|
+
|
|
1014
|
+
def _apply_time_filters(self, nodes: List[GraphNode], filters: Optional[JSONDict]) -> List[GraphNode]:
|
|
1015
|
+
"""Apply time-based filters to a list of nodes."""
|
|
1016
|
+
if not filters:
|
|
1017
|
+
return nodes
|
|
1018
|
+
|
|
1019
|
+
filtered = nodes
|
|
1020
|
+
|
|
1021
|
+
since_val = filters.get("since")
|
|
1022
|
+
if since_val:
|
|
1023
|
+
since_dt: datetime
|
|
1024
|
+
if isinstance(since_val, str):
|
|
1025
|
+
since_dt = datetime.fromisoformat(since_val)
|
|
1026
|
+
elif isinstance(since_val, datetime):
|
|
1027
|
+
since_dt = since_val
|
|
1028
|
+
else:
|
|
1029
|
+
# Skip invalid type
|
|
1030
|
+
return filtered
|
|
1031
|
+
filtered = [n for n in filtered if n.updated_at and n.updated_at >= since_dt]
|
|
1032
|
+
|
|
1033
|
+
until_val = filters.get("until")
|
|
1034
|
+
if until_val:
|
|
1035
|
+
until_dt: datetime
|
|
1036
|
+
if isinstance(until_val, str):
|
|
1037
|
+
until_dt = datetime.fromisoformat(until_val)
|
|
1038
|
+
elif isinstance(until_val, datetime):
|
|
1039
|
+
until_dt = until_val
|
|
1040
|
+
else:
|
|
1041
|
+
# Skip invalid type
|
|
1042
|
+
return filtered
|
|
1043
|
+
filtered = [n for n in filtered if n.updated_at and n.updated_at <= until_dt]
|
|
1044
|
+
|
|
1045
|
+
return filtered
|
|
1046
|
+
|
|
1047
|
+
def _apply_tag_filters(self, nodes: List[GraphNode], filters: Optional[JSONDict]) -> List[GraphNode]:
|
|
1048
|
+
"""Apply tag-based filters to a list of nodes."""
|
|
1049
|
+
if not filters or "tags" not in filters:
|
|
1050
|
+
return nodes
|
|
1051
|
+
|
|
1052
|
+
tags_val = filters.get("tags", [])
|
|
1053
|
+
if not isinstance(tags_val, list):
|
|
1054
|
+
return nodes
|
|
1055
|
+
|
|
1056
|
+
filtered = []
|
|
1057
|
+
for n in nodes:
|
|
1058
|
+
if not n.attributes:
|
|
1059
|
+
continue
|
|
1060
|
+
|
|
1061
|
+
# Handle both dict and object attributes
|
|
1062
|
+
node_tags = None
|
|
1063
|
+
if isinstance(n.attributes, dict):
|
|
1064
|
+
node_tags = get_list(n.attributes, "tags", [])
|
|
1065
|
+
elif hasattr(n.attributes, "tags"):
|
|
1066
|
+
node_tags = n.attributes.tags
|
|
1067
|
+
|
|
1068
|
+
if node_tags and any(tag in node_tags for tag in tags_val):
|
|
1069
|
+
filtered.append(n)
|
|
1070
|
+
|
|
1071
|
+
return filtered
|
|
1072
|
+
|
|
1073
|
+
def _parse_search_query(self, query: str) -> Tuple[List[str], Optional[str], Optional[GraphScope]]:
|
|
1074
|
+
"""Parse search query string for terms and filters."""
|
|
1075
|
+
if not query:
|
|
1076
|
+
return [], None, None
|
|
1077
|
+
|
|
1078
|
+
query_parts = query.split()
|
|
1079
|
+
search_terms = []
|
|
1080
|
+
node_type = None
|
|
1081
|
+
scope = None
|
|
1082
|
+
|
|
1083
|
+
for part in query_parts:
|
|
1084
|
+
if part.startswith("type:"):
|
|
1085
|
+
node_type = part.split(":")[1]
|
|
1086
|
+
elif part.startswith("scope:"):
|
|
1087
|
+
scope = GraphScope(part.split(":")[1].lower())
|
|
1088
|
+
else:
|
|
1089
|
+
search_terms.append(part.lower())
|
|
1090
|
+
|
|
1091
|
+
return search_terms, node_type, scope
|
|
1092
|
+
|
|
1093
|
+
def _filter_nodes_by_content(self, nodes: List[GraphNode], search_terms: List[str]) -> List[GraphNode]:
|
|
1094
|
+
"""Filter nodes by search terms in content."""
|
|
1095
|
+
if not search_terms:
|
|
1096
|
+
return nodes
|
|
1097
|
+
|
|
1098
|
+
filtered = []
|
|
1099
|
+
for node in nodes:
|
|
1100
|
+
# Search in node ID
|
|
1101
|
+
if any(term in node.id.lower() for term in search_terms):
|
|
1102
|
+
filtered.append(node)
|
|
1103
|
+
continue
|
|
1104
|
+
|
|
1105
|
+
# Search in attributes
|
|
1106
|
+
if node.attributes:
|
|
1107
|
+
attrs_str = json.dumps(node.attributes, cls=DateTimeEncoder).lower()
|
|
1108
|
+
if any(term in attrs_str for term in search_terms):
|
|
1109
|
+
filtered.append(node)
|
|
1110
|
+
|
|
1111
|
+
return filtered
|
|
1112
|
+
|
|
1113
|
+
def _get_attributes_dict(self, attributes: Any) -> JSONDict:
|
|
1114
|
+
"""Extract attributes as dictionary from various formats."""
|
|
1115
|
+
if hasattr(attributes, "model_dump"):
|
|
1116
|
+
return attributes.model_dump() # type: ignore[no-any-return]
|
|
1117
|
+
elif attributes:
|
|
1118
|
+
return dict(attributes)
|
|
1119
|
+
else:
|
|
1120
|
+
return {}
|