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,1337 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Helper functions for telemetry service refactoring.
|
|
3
|
+
|
|
4
|
+
These break down the complex get_telemetry_summary method into focused,
|
|
5
|
+
testable components. All functions fail fast and loud - no fallback data.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from datetime import datetime, timedelta, timezone
|
|
10
|
+
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, TypeVar, Union
|
|
11
|
+
|
|
12
|
+
from ciris_engine.schemas.types import JSONDict
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
from ciris_engine.logic.services.graph.telemetry_service.exceptions import (
|
|
17
|
+
MemoryBusUnavailableError,
|
|
18
|
+
MetricCollectionError,
|
|
19
|
+
NoThoughtDataError,
|
|
20
|
+
QueueStatusUnavailableError,
|
|
21
|
+
RuntimeControlBusUnavailableError,
|
|
22
|
+
ServiceStartTimeUnavailableError,
|
|
23
|
+
ThoughtDepthQueryError,
|
|
24
|
+
UnknownMetricTypeError,
|
|
25
|
+
)
|
|
26
|
+
from ciris_engine.schemas.runtime.system_context import ContinuitySummary, TelemetrySummary
|
|
27
|
+
from ciris_engine.schemas.services.graph.telemetry import MetricAggregates, MetricRecord
|
|
28
|
+
|
|
29
|
+
# TypeVar for summary cache
|
|
30
|
+
SummaryType = TypeVar("SummaryType", TelemetrySummary, ContinuitySummary)
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from ciris_engine.logic.buses.memory_bus import MemoryBus
|
|
34
|
+
from ciris_engine.logic.buses.runtime_control_bus import RuntimeControlBus
|
|
35
|
+
from ciris_engine.logic.services.graph.telemetry_service.service import GraphTelemetryService
|
|
36
|
+
from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
|
|
37
|
+
|
|
38
|
+
# Metric types to query - moved from inline definition
|
|
39
|
+
METRIC_TYPES = [
|
|
40
|
+
("llm.tokens.total", "tokens"),
|
|
41
|
+
("llm_tokens_used", "tokens"), # Legacy metric name
|
|
42
|
+
("llm.tokens.input", "tokens"),
|
|
43
|
+
("llm.tokens.output", "tokens"),
|
|
44
|
+
("llm.cost.cents", "cost"),
|
|
45
|
+
("llm.environmental.carbon_grams", "carbon"),
|
|
46
|
+
("llm.environmental.energy_kwh", "energy"),
|
|
47
|
+
("llm.latency.ms", "latency"),
|
|
48
|
+
("thought_processing_completed", "thoughts"),
|
|
49
|
+
("thought_processing_started", "thoughts"),
|
|
50
|
+
("action_selected_task_complete", "tasks"),
|
|
51
|
+
("handler_invoked_total", "messages"),
|
|
52
|
+
("error.occurred", "errors"),
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# ============================================================================
|
|
57
|
+
# METRIC COLLECTION HELPERS
|
|
58
|
+
# ============================================================================
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
async def collect_metric_aggregates(
|
|
62
|
+
telemetry_service: "GraphTelemetryService",
|
|
63
|
+
metric_types: List[Tuple[str, str]],
|
|
64
|
+
window_start_24h: datetime,
|
|
65
|
+
window_start_1h: datetime,
|
|
66
|
+
window_end: datetime,
|
|
67
|
+
) -> MetricAggregates:
|
|
68
|
+
"""Collect and aggregate metrics across time windows.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
telemetry_service: The telemetry service instance
|
|
72
|
+
metric_types: List of (metric_name, metric_type) tuples to query
|
|
73
|
+
window_start_24h: Start of 24-hour window
|
|
74
|
+
window_start_1h: Start of 1-hour window
|
|
75
|
+
window_end: End of both windows
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
MetricAggregates schema with all collected metrics
|
|
79
|
+
|
|
80
|
+
Raises:
|
|
81
|
+
MetricCollectionError: If metric collection fails
|
|
82
|
+
InvalidMetricDataError: If metric data is invalid
|
|
83
|
+
"""
|
|
84
|
+
aggregates = MetricAggregates()
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
for metric_name, metric_type in metric_types:
|
|
88
|
+
# Get 24h data
|
|
89
|
+
day_metrics: List[MetricRecord] = await telemetry_service.query_metrics(
|
|
90
|
+
metric_name=metric_name, start_time=window_start_24h, end_time=window_end
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
for metric in day_metrics:
|
|
94
|
+
# Aggregate into appropriate counter
|
|
95
|
+
aggregate_metric_by_type(
|
|
96
|
+
metric_type, metric.value, metric.timestamp, metric.tags, aggregates, window_start_1h
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
return aggregates
|
|
100
|
+
|
|
101
|
+
except Exception as e:
|
|
102
|
+
raise MetricCollectionError(f"Failed to collect metric aggregates: {e}") from e
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _update_windowed_metric(
|
|
106
|
+
aggregates: MetricAggregates,
|
|
107
|
+
field_24h: str,
|
|
108
|
+
field_1h: str,
|
|
109
|
+
value: float,
|
|
110
|
+
in_1h_window: bool,
|
|
111
|
+
converter: Callable[[float], Union[int, float]] = float,
|
|
112
|
+
) -> None:
|
|
113
|
+
"""Update a metric with both 24h and 1h windows.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
aggregates: MetricAggregates object to update
|
|
117
|
+
field_24h: Name of 24h field to update
|
|
118
|
+
field_1h: Name of 1h field to update
|
|
119
|
+
value: Value to add
|
|
120
|
+
in_1h_window: Whether metric is in 1h window
|
|
121
|
+
converter: Function to convert value (int or float)
|
|
122
|
+
"""
|
|
123
|
+
setattr(aggregates, field_24h, getattr(aggregates, field_24h) + converter(value))
|
|
124
|
+
if in_1h_window:
|
|
125
|
+
setattr(aggregates, field_1h, getattr(aggregates, field_1h) + converter(value))
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _handle_tokens_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
|
|
129
|
+
"""Handle tokens metric aggregation."""
|
|
130
|
+
_update_windowed_metric(aggregates, "tokens_24h", "tokens_1h", value, in_1h_window, int)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _handle_cost_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
|
|
134
|
+
"""Handle cost metric aggregation."""
|
|
135
|
+
_update_windowed_metric(aggregates, "cost_24h_cents", "cost_1h_cents", value, in_1h_window, float)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _handle_carbon_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
|
|
139
|
+
"""Handle carbon metric aggregation."""
|
|
140
|
+
_update_windowed_metric(aggregates, "carbon_24h_grams", "carbon_1h_grams", value, in_1h_window, float)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _handle_energy_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
|
|
144
|
+
"""Handle energy metric aggregation."""
|
|
145
|
+
_update_windowed_metric(aggregates, "energy_24h_kwh", "energy_1h_kwh", value, in_1h_window, float)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _handle_messages_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
|
|
149
|
+
"""Handle messages metric aggregation."""
|
|
150
|
+
_update_windowed_metric(aggregates, "messages_24h", "messages_1h", value, in_1h_window, int)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _handle_thoughts_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool) -> None:
|
|
154
|
+
"""Handle thoughts metric aggregation."""
|
|
155
|
+
_update_windowed_metric(aggregates, "thoughts_24h", "thoughts_1h", value, in_1h_window, int)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _handle_tasks_metric(aggregates: MetricAggregates, value: float) -> None:
|
|
159
|
+
"""Handle tasks metric aggregation (24h only, no 1h tracking)."""
|
|
160
|
+
aggregates.tasks_24h += int(value)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _handle_errors_metric(aggregates: MetricAggregates, value: float, in_1h_window: bool, tags: Dict[str, str]) -> None:
|
|
164
|
+
"""Handle errors metric aggregation."""
|
|
165
|
+
_update_windowed_metric(aggregates, "errors_24h", "errors_1h", value, in_1h_window, int)
|
|
166
|
+
# Track errors by service
|
|
167
|
+
service = tags.get("service", "unknown")
|
|
168
|
+
aggregates.service_errors[service] = aggregates.service_errors.get(service, 0) + 1
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _handle_latency_metric(aggregates: MetricAggregates, value: float, tags: Dict[str, str]) -> None:
|
|
172
|
+
"""Handle latency metric aggregation (service-level, no time windowing)."""
|
|
173
|
+
service = tags.get("service", "unknown")
|
|
174
|
+
if service not in aggregates.service_latency:
|
|
175
|
+
aggregates.service_latency[service] = []
|
|
176
|
+
aggregates.service_latency[service].append(float(value))
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# Handler type definition
|
|
180
|
+
MetricHandlerFunc = Callable[[MetricAggregates, float, bool, Dict[str, str]], None]
|
|
181
|
+
|
|
182
|
+
# Metric type dispatch table
|
|
183
|
+
_METRIC_HANDLERS: Dict[str, MetricHandlerFunc] = {
|
|
184
|
+
"tokens": lambda agg, val, win, tags: _handle_tokens_metric(agg, val, win),
|
|
185
|
+
"cost": lambda agg, val, win, tags: _handle_cost_metric(agg, val, win),
|
|
186
|
+
"carbon": lambda agg, val, win, tags: _handle_carbon_metric(agg, val, win),
|
|
187
|
+
"energy": lambda agg, val, win, tags: _handle_energy_metric(agg, val, win),
|
|
188
|
+
"messages": lambda agg, val, win, tags: _handle_messages_metric(agg, val, win),
|
|
189
|
+
"thoughts": lambda agg, val, win, tags: _handle_thoughts_metric(agg, val, win),
|
|
190
|
+
"tasks": lambda agg, val, win, tags: _handle_tasks_metric(agg, val),
|
|
191
|
+
"errors": lambda agg, val, win, tags: _handle_errors_metric(agg, val, win, tags),
|
|
192
|
+
"latency": lambda agg, val, win, tags: _handle_latency_metric(agg, val, tags),
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def aggregate_metric_by_type(
|
|
197
|
+
metric_type: str,
|
|
198
|
+
value: float,
|
|
199
|
+
timestamp: datetime,
|
|
200
|
+
tags: Dict[str, str],
|
|
201
|
+
aggregates: MetricAggregates,
|
|
202
|
+
window_start_1h: datetime,
|
|
203
|
+
) -> None:
|
|
204
|
+
"""Aggregate a single metric value into the appropriate counters.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
metric_type: Type of metric (tokens, cost, carbon, etc.)
|
|
208
|
+
value: Numeric value from metric
|
|
209
|
+
timestamp: When the metric occurred
|
|
210
|
+
tags: Metric tags (service, etc.)
|
|
211
|
+
aggregates: MetricAggregates object to update (mutated)
|
|
212
|
+
window_start_1h: Start of 1-hour window for filtering
|
|
213
|
+
|
|
214
|
+
Raises:
|
|
215
|
+
UnknownMetricTypeError: If metric_type is not recognized
|
|
216
|
+
"""
|
|
217
|
+
# Check if timestamp is in 1h window
|
|
218
|
+
in_1h_window = timestamp >= window_start_1h
|
|
219
|
+
|
|
220
|
+
# Dispatch to appropriate handler
|
|
221
|
+
handler = _METRIC_HANDLERS.get(metric_type)
|
|
222
|
+
if not handler:
|
|
223
|
+
raise UnknownMetricTypeError(f"Unknown metric type: {metric_type}")
|
|
224
|
+
|
|
225
|
+
handler(aggregates, value, in_1h_window, tags)
|
|
226
|
+
|
|
227
|
+
# Track service calls
|
|
228
|
+
if "service" in tags:
|
|
229
|
+
service = tags["service"]
|
|
230
|
+
aggregates.service_calls[service] = aggregates.service_calls.get(service, 0) + 1
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
# ============================================================================
|
|
234
|
+
# EXTERNAL DATA COLLECTION HELPERS
|
|
235
|
+
# ============================================================================
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
async def get_average_thought_depth(
|
|
239
|
+
memory_bus: Optional["MemoryBus"],
|
|
240
|
+
window_start: datetime,
|
|
241
|
+
) -> float:
|
|
242
|
+
"""Get average thought depth from the last 24 hours.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
memory_bus: Memory bus to access persistence
|
|
246
|
+
window_start: Start of time window
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Average thought depth (must be valid positive number)
|
|
250
|
+
|
|
251
|
+
Raises:
|
|
252
|
+
MemoryBusUnavailableError: If memory bus not available
|
|
253
|
+
ThoughtDepthQueryError: If database query fails
|
|
254
|
+
NoThoughtDataError: If no thought data available in window
|
|
255
|
+
"""
|
|
256
|
+
if not memory_bus:
|
|
257
|
+
raise MemoryBusUnavailableError("Memory bus is not available")
|
|
258
|
+
|
|
259
|
+
try:
|
|
260
|
+
from ciris_engine.logic.persistence import get_db_connection
|
|
261
|
+
|
|
262
|
+
# Get the memory service to access its db_path
|
|
263
|
+
memory_service = await memory_bus.get_service(handler_name="telemetry_service")
|
|
264
|
+
if not memory_service:
|
|
265
|
+
raise MemoryBusUnavailableError("Memory service not found on memory bus")
|
|
266
|
+
|
|
267
|
+
db_path = getattr(memory_service, "db_path", None)
|
|
268
|
+
if not db_path:
|
|
269
|
+
raise ThoughtDepthQueryError("Memory service has no db_path attribute")
|
|
270
|
+
|
|
271
|
+
from ciris_engine.logic.persistence.db.dialect import get_adapter
|
|
272
|
+
|
|
273
|
+
adapter = get_adapter()
|
|
274
|
+
|
|
275
|
+
with get_db_connection(db_path=db_path) as conn:
|
|
276
|
+
cursor = conn.cursor()
|
|
277
|
+
# Use window_start parameter for consistent timing with other telemetry calculations
|
|
278
|
+
# Use dialect-appropriate placeholder
|
|
279
|
+
sql = f"""
|
|
280
|
+
SELECT AVG(thought_depth) as avg_depth
|
|
281
|
+
FROM thoughts
|
|
282
|
+
WHERE created_at >= {adapter.placeholder()}
|
|
283
|
+
"""
|
|
284
|
+
cursor.execute(sql, (window_start.isoformat(),))
|
|
285
|
+
result = cursor.fetchone()
|
|
286
|
+
|
|
287
|
+
# Handle both dict (PostgreSQL RealDictCursor/SQLite Row) and tuple results
|
|
288
|
+
if result:
|
|
289
|
+
if isinstance(result, dict):
|
|
290
|
+
avg_depth = result.get("avg_depth")
|
|
291
|
+
elif hasattr(result, "keys"):
|
|
292
|
+
# SQLite Row or dict-like object
|
|
293
|
+
avg_depth = result["avg_depth"]
|
|
294
|
+
else:
|
|
295
|
+
# Tuple result - first column is avg_depth
|
|
296
|
+
avg_depth = result[0] if result else None
|
|
297
|
+
|
|
298
|
+
if avg_depth is not None:
|
|
299
|
+
return float(avg_depth)
|
|
300
|
+
|
|
301
|
+
raise NoThoughtDataError("No thought data available in the last 24 hours")
|
|
302
|
+
|
|
303
|
+
except NoThoughtDataError:
|
|
304
|
+
raise # Re-raise as-is
|
|
305
|
+
except Exception as e:
|
|
306
|
+
raise ThoughtDepthQueryError(f"Failed to query thought depth: {e}") from e
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
async def get_queue_saturation(
|
|
310
|
+
runtime_control_bus: Optional["RuntimeControlBus"],
|
|
311
|
+
) -> float:
|
|
312
|
+
"""Get current processor queue saturation (0.0-1.0).
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
runtime_control_bus: Runtime control bus to access queue status
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
Queue saturation ratio between 0.0 and 1.0
|
|
319
|
+
|
|
320
|
+
Raises:
|
|
321
|
+
RuntimeControlBusUnavailableError: If runtime control bus not available
|
|
322
|
+
QueueStatusUnavailableError: If queue status cannot be retrieved
|
|
323
|
+
"""
|
|
324
|
+
if not runtime_control_bus:
|
|
325
|
+
raise RuntimeControlBusUnavailableError("Runtime control bus is not available")
|
|
326
|
+
|
|
327
|
+
try:
|
|
328
|
+
runtime_control = await runtime_control_bus.get_service(handler_name="telemetry_service")
|
|
329
|
+
if not runtime_control:
|
|
330
|
+
raise RuntimeControlBusUnavailableError("Runtime control service not found on bus")
|
|
331
|
+
|
|
332
|
+
processor_queue_status = await runtime_control.get_processor_queue_status()
|
|
333
|
+
if not processor_queue_status:
|
|
334
|
+
raise QueueStatusUnavailableError("get_processor_queue_status returned None")
|
|
335
|
+
|
|
336
|
+
if processor_queue_status.max_size <= 0:
|
|
337
|
+
raise QueueStatusUnavailableError(f"Invalid max_size: {processor_queue_status.max_size}")
|
|
338
|
+
|
|
339
|
+
queue_saturation = processor_queue_status.queue_size / processor_queue_status.max_size
|
|
340
|
+
# Clamp to 0-1 range
|
|
341
|
+
return float(min(1.0, max(0.0, queue_saturation)))
|
|
342
|
+
|
|
343
|
+
except (RuntimeControlBusUnavailableError, QueueStatusUnavailableError):
|
|
344
|
+
raise # Re-raise as-is
|
|
345
|
+
except Exception as e:
|
|
346
|
+
raise QueueStatusUnavailableError(f"Failed to get queue saturation: {e}") from e
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def get_service_uptime(
|
|
350
|
+
start_time: Optional[datetime],
|
|
351
|
+
now: datetime,
|
|
352
|
+
) -> float:
|
|
353
|
+
"""Get service uptime in seconds.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
start_time: When the service started (or None)
|
|
357
|
+
now: Current time
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
Uptime in seconds
|
|
361
|
+
|
|
362
|
+
Raises:
|
|
363
|
+
ServiceStartTimeUnavailableError: If start_time is None
|
|
364
|
+
"""
|
|
365
|
+
if start_time is None:
|
|
366
|
+
raise ServiceStartTimeUnavailableError("Service start_time has not been set")
|
|
367
|
+
|
|
368
|
+
return (now - start_time).total_seconds()
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
# ============================================================================
|
|
372
|
+
# CALCULATION HELPERS
|
|
373
|
+
# ============================================================================
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def calculate_error_rate(
|
|
377
|
+
errors_24h: int,
|
|
378
|
+
total_operations: int,
|
|
379
|
+
) -> float:
|
|
380
|
+
"""Calculate error rate percentage.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
errors_24h: Number of errors in 24h window
|
|
384
|
+
total_operations: Total operations (messages + thoughts + tasks)
|
|
385
|
+
|
|
386
|
+
Returns:
|
|
387
|
+
Error rate as percentage (0.0-100.0)
|
|
388
|
+
"""
|
|
389
|
+
if total_operations == 0:
|
|
390
|
+
return 0.0
|
|
391
|
+
return (errors_24h / total_operations) * 100.0
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def calculate_average_latencies(
|
|
395
|
+
service_latency: Dict[str, List[float]],
|
|
396
|
+
) -> Dict[str, float]:
|
|
397
|
+
"""Calculate average latency per service.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
service_latency: Map of service name to list of latency values
|
|
401
|
+
|
|
402
|
+
Returns:
|
|
403
|
+
Map of service name to average latency in ms
|
|
404
|
+
"""
|
|
405
|
+
result = {}
|
|
406
|
+
for service, latencies in service_latency.items():
|
|
407
|
+
if latencies:
|
|
408
|
+
result[service] = sum(latencies) / len(latencies)
|
|
409
|
+
return result
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
# ============================================================================
|
|
413
|
+
# CACHE HELPERS
|
|
414
|
+
# ============================================================================
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def check_summary_cache(
|
|
418
|
+
cache: Dict[str, Tuple[datetime, Any]],
|
|
419
|
+
cache_key: str,
|
|
420
|
+
now: datetime,
|
|
421
|
+
ttl_seconds: int,
|
|
422
|
+
) -> Optional[Any]:
|
|
423
|
+
"""Check if cached summary is still valid.
|
|
424
|
+
|
|
425
|
+
Args:
|
|
426
|
+
cache: Summary cache dictionary
|
|
427
|
+
cache_key: Key to look up in cache
|
|
428
|
+
now: Current time
|
|
429
|
+
ttl_seconds: Cache TTL in seconds
|
|
430
|
+
|
|
431
|
+
Returns:
|
|
432
|
+
Cached summary (TelemetrySummary or ContinuitySummary) if valid, None otherwise
|
|
433
|
+
"""
|
|
434
|
+
if cache_key in cache:
|
|
435
|
+
cached_time, cached_summary = cache[cache_key]
|
|
436
|
+
if (now - cached_time).total_seconds() < ttl_seconds:
|
|
437
|
+
return cached_summary
|
|
438
|
+
return None
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def store_summary_cache(
|
|
442
|
+
cache: Dict[str, Tuple[datetime, Any]],
|
|
443
|
+
cache_key: str,
|
|
444
|
+
now: datetime,
|
|
445
|
+
summary: Any,
|
|
446
|
+
) -> None:
|
|
447
|
+
"""Store summary in cache.
|
|
448
|
+
|
|
449
|
+
Args:
|
|
450
|
+
cache: Summary cache dictionary (mutated)
|
|
451
|
+
cache_key: Key to store under
|
|
452
|
+
now: Current time
|
|
453
|
+
summary: Summary to cache
|
|
454
|
+
"""
|
|
455
|
+
cache[cache_key] = (now, summary)
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
# ============================================================================
|
|
459
|
+
# SCHEMA BUILDERS
|
|
460
|
+
# ============================================================================
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
def _extract_service_stats_cb_data(stats: JSONDict) -> "CircuitBreakerState":
|
|
464
|
+
"""Extract circuit breaker data from service stats dict.
|
|
465
|
+
|
|
466
|
+
Args:
|
|
467
|
+
stats: Service stats dict containing circuit_breaker_state
|
|
468
|
+
|
|
469
|
+
Returns:
|
|
470
|
+
CircuitBreakerState with state and metrics
|
|
471
|
+
"""
|
|
472
|
+
# Import at runtime to avoid circular dependency
|
|
473
|
+
from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
|
|
474
|
+
|
|
475
|
+
return CircuitBreakerState(
|
|
476
|
+
state=stats.get("circuit_breaker_state", "unknown"),
|
|
477
|
+
total_requests=stats.get("total_requests", 0),
|
|
478
|
+
failed_requests=stats.get("failed_requests", 0),
|
|
479
|
+
failure_rate=stats.get("failure_rate", "0.00%"),
|
|
480
|
+
consecutive_failures=stats.get("consecutive_failures", 0),
|
|
481
|
+
failure_count=stats.get("consecutive_failures", 0),
|
|
482
|
+
success_count=0,
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
def _extract_direct_cb_data(cb: Any) -> "CircuitBreakerState":
|
|
487
|
+
"""Extract circuit breaker data from CircuitBreaker object.
|
|
488
|
+
|
|
489
|
+
Args:
|
|
490
|
+
cb: CircuitBreaker instance
|
|
491
|
+
|
|
492
|
+
Returns:
|
|
493
|
+
CircuitBreakerState with state and counts
|
|
494
|
+
"""
|
|
495
|
+
from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
|
|
496
|
+
|
|
497
|
+
return CircuitBreakerState(
|
|
498
|
+
state=str(cb.state) if hasattr(cb, "state") else "unknown",
|
|
499
|
+
failure_count=cb.failure_count if hasattr(cb, "failure_count") else 0,
|
|
500
|
+
success_count=cb.success_count if hasattr(cb, "success_count") else 0,
|
|
501
|
+
total_requests=0,
|
|
502
|
+
failed_requests=0,
|
|
503
|
+
consecutive_failures=cb.failure_count if hasattr(cb, "failure_count") else 0,
|
|
504
|
+
failure_rate="0.00%",
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
def _collect_from_service_stats(bus: Any) -> Dict[str, "CircuitBreakerState"]:
|
|
509
|
+
"""Collect circuit breaker data from bus.get_service_stats().
|
|
510
|
+
|
|
511
|
+
Args:
|
|
512
|
+
bus: Bus instance with get_service_stats method
|
|
513
|
+
|
|
514
|
+
Returns:
|
|
515
|
+
Dict mapping service names to their circuit breaker state
|
|
516
|
+
"""
|
|
517
|
+
from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
|
|
518
|
+
|
|
519
|
+
cb_data: Dict[str, CircuitBreakerState] = {}
|
|
520
|
+
|
|
521
|
+
try:
|
|
522
|
+
service_stats = bus.get_service_stats()
|
|
523
|
+
if not isinstance(service_stats, dict):
|
|
524
|
+
return cb_data
|
|
525
|
+
|
|
526
|
+
for svc_name, stats in service_stats.items():
|
|
527
|
+
if isinstance(stats, dict) and "circuit_breaker_state" in stats:
|
|
528
|
+
cb_data[svc_name] = _extract_service_stats_cb_data(stats)
|
|
529
|
+
|
|
530
|
+
except Exception:
|
|
531
|
+
# Silently skip buses that fail to provide stats
|
|
532
|
+
pass
|
|
533
|
+
|
|
534
|
+
return cb_data
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
def _collect_from_direct_cb_attribute(
|
|
538
|
+
bus: Any, existing_data: Dict[str, "CircuitBreakerState"]
|
|
539
|
+
) -> Dict[str, "CircuitBreakerState"]:
|
|
540
|
+
"""Collect circuit breaker data from bus.circuit_breakers attribute.
|
|
541
|
+
|
|
542
|
+
Args:
|
|
543
|
+
bus: Bus instance with circuit_breakers attribute
|
|
544
|
+
existing_data: Already collected CB data (don't override these)
|
|
545
|
+
|
|
546
|
+
Returns:
|
|
547
|
+
Dict mapping service names to their circuit breaker state
|
|
548
|
+
"""
|
|
549
|
+
from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
|
|
550
|
+
|
|
551
|
+
cb_data: Dict[str, CircuitBreakerState] = {}
|
|
552
|
+
|
|
553
|
+
try:
|
|
554
|
+
circuit_breakers = bus.circuit_breakers
|
|
555
|
+
if not isinstance(circuit_breakers, dict):
|
|
556
|
+
return cb_data
|
|
557
|
+
|
|
558
|
+
for cb_name, cb in circuit_breakers.items():
|
|
559
|
+
if cb_name not in existing_data: # Don't override if already collected
|
|
560
|
+
cb_data[cb_name] = _extract_direct_cb_data(cb)
|
|
561
|
+
|
|
562
|
+
except Exception:
|
|
563
|
+
# Silently skip
|
|
564
|
+
pass
|
|
565
|
+
|
|
566
|
+
return cb_data
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
def _collect_from_single_bus(bus: Any) -> Dict[str, "CircuitBreakerState"]:
|
|
570
|
+
"""Collect circuit breaker data from a single bus.
|
|
571
|
+
|
|
572
|
+
Args:
|
|
573
|
+
bus: Bus instance to collect from
|
|
574
|
+
|
|
575
|
+
Returns:
|
|
576
|
+
Dict mapping service names to their circuit breaker state
|
|
577
|
+
"""
|
|
578
|
+
from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
|
|
579
|
+
|
|
580
|
+
cb_data: Dict[str, CircuitBreakerState] = {}
|
|
581
|
+
|
|
582
|
+
# Try get_service_stats first
|
|
583
|
+
if hasattr(bus, "get_service_stats"):
|
|
584
|
+
logger.debug("[CB COLLECT] Bus has get_service_stats method")
|
|
585
|
+
cb_data.update(_collect_from_service_stats(bus))
|
|
586
|
+
logger.debug(f"[CB COLLECT] Collected {len(cb_data)} CBs from service_stats")
|
|
587
|
+
|
|
588
|
+
# Also check direct circuit_breakers attribute
|
|
589
|
+
if hasattr(bus, "circuit_breakers"):
|
|
590
|
+
cb_attr = getattr(bus, "circuit_breakers", {})
|
|
591
|
+
logger.debug(
|
|
592
|
+
f"[CB COLLECT] Bus has circuit_breakers attribute with {len(cb_attr) if isinstance(cb_attr, dict) else 0} entries"
|
|
593
|
+
)
|
|
594
|
+
cb_data.update(_collect_from_direct_cb_attribute(bus, cb_data))
|
|
595
|
+
logger.debug(f"[CB COLLECT] Total {len(cb_data)} CBs after checking circuit_breakers attribute")
|
|
596
|
+
|
|
597
|
+
return cb_data
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def collect_circuit_breaker_state(runtime: Any) -> Dict[str, "CircuitBreakerState"]:
|
|
601
|
+
"""Collect circuit breaker state from all buses.
|
|
602
|
+
|
|
603
|
+
Walks through all buses (LLM, Memory, Communication, Tool, Wise, RuntimeControl)
|
|
604
|
+
via the runtime's bus_manager and collects their circuit breaker states.
|
|
605
|
+
|
|
606
|
+
Args:
|
|
607
|
+
runtime: Runtime instance with bus_manager attribute
|
|
608
|
+
|
|
609
|
+
Returns:
|
|
610
|
+
Dict mapping service names to their circuit breaker state
|
|
611
|
+
"""
|
|
612
|
+
from ciris_engine.schemas.services.graph.telemetry import CircuitBreakerState
|
|
613
|
+
|
|
614
|
+
circuit_breaker_data: Dict[str, CircuitBreakerState] = {}
|
|
615
|
+
|
|
616
|
+
if not runtime:
|
|
617
|
+
logger.debug("[CB COLLECT] No runtime provided")
|
|
618
|
+
return circuit_breaker_data
|
|
619
|
+
|
|
620
|
+
try:
|
|
621
|
+
bus_manager = getattr(runtime, "bus_manager", None)
|
|
622
|
+
if not bus_manager:
|
|
623
|
+
logger.debug(f"[CB COLLECT] Runtime has no bus_manager (type: {type(runtime).__name__})")
|
|
624
|
+
return circuit_breaker_data
|
|
625
|
+
|
|
626
|
+
# List of bus attributes to check
|
|
627
|
+
bus_names = ["llm", "memory", "communication", "wise", "tool", "runtime_control"]
|
|
628
|
+
|
|
629
|
+
for bus_name in bus_names:
|
|
630
|
+
bus = getattr(bus_manager, bus_name, None)
|
|
631
|
+
if bus:
|
|
632
|
+
logger.debug(f"[CB COLLECT] Collecting from {bus_name} bus ({type(bus).__name__})")
|
|
633
|
+
bus_data = _collect_from_single_bus(bus)
|
|
634
|
+
if bus_data:
|
|
635
|
+
logger.debug(f"[CB COLLECT] Found {len(bus_data)} circuit breakers in {bus_name} bus")
|
|
636
|
+
circuit_breaker_data.update(bus_data)
|
|
637
|
+
else:
|
|
638
|
+
logger.debug(f"[CB COLLECT] No {bus_name} bus in bus_manager")
|
|
639
|
+
|
|
640
|
+
logger.debug(f"[CB COLLECT] Total circuit breakers collected: {len(circuit_breaker_data)}")
|
|
641
|
+
|
|
642
|
+
except Exception as e:
|
|
643
|
+
# If anything fails, return whatever we collected so far
|
|
644
|
+
logger.warning(f"[CB COLLECT] Error collecting circuit breakers: {e}")
|
|
645
|
+
|
|
646
|
+
return circuit_breaker_data
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
def build_telemetry_summary(
|
|
650
|
+
window_start: datetime,
|
|
651
|
+
window_end: datetime,
|
|
652
|
+
uptime_seconds: float,
|
|
653
|
+
aggregates: MetricAggregates,
|
|
654
|
+
error_rate: float,
|
|
655
|
+
avg_thought_depth: float,
|
|
656
|
+
queue_saturation: float,
|
|
657
|
+
service_latency_ms: Dict[str, float],
|
|
658
|
+
circuit_breaker: Optional[Dict[str, "CircuitBreakerState"]] = None,
|
|
659
|
+
) -> TelemetrySummary:
|
|
660
|
+
"""Build TelemetrySummary from collected data.
|
|
661
|
+
|
|
662
|
+
Args:
|
|
663
|
+
window_start: Start of time window
|
|
664
|
+
window_end: End of time window
|
|
665
|
+
uptime_seconds: Service uptime
|
|
666
|
+
aggregates: Collected metric aggregates
|
|
667
|
+
error_rate: Calculated error rate percentage
|
|
668
|
+
avg_thought_depth: Average thought depth
|
|
669
|
+
queue_saturation: Queue saturation ratio
|
|
670
|
+
service_latency_ms: Service latency map
|
|
671
|
+
circuit_breaker: Circuit breaker state across all services
|
|
672
|
+
|
|
673
|
+
Returns:
|
|
674
|
+
Validated TelemetrySummary schema
|
|
675
|
+
"""
|
|
676
|
+
return TelemetrySummary(
|
|
677
|
+
window_start=window_start,
|
|
678
|
+
window_end=window_end,
|
|
679
|
+
uptime_seconds=uptime_seconds,
|
|
680
|
+
messages_processed_24h=aggregates.messages_24h,
|
|
681
|
+
thoughts_processed_24h=aggregates.thoughts_24h,
|
|
682
|
+
tasks_completed_24h=aggregates.tasks_24h,
|
|
683
|
+
errors_24h=aggregates.errors_24h,
|
|
684
|
+
messages_current_hour=aggregates.messages_1h,
|
|
685
|
+
thoughts_current_hour=aggregates.thoughts_1h,
|
|
686
|
+
errors_current_hour=aggregates.errors_1h,
|
|
687
|
+
service_calls=aggregates.service_calls,
|
|
688
|
+
service_errors=aggregates.service_errors,
|
|
689
|
+
service_latency_ms=service_latency_ms,
|
|
690
|
+
tokens_last_hour=float(aggregates.tokens_1h),
|
|
691
|
+
cost_last_hour_cents=aggregates.cost_1h_cents,
|
|
692
|
+
carbon_last_hour_grams=aggregates.carbon_1h_grams,
|
|
693
|
+
energy_last_hour_kwh=aggregates.energy_1h_kwh,
|
|
694
|
+
tokens_24h=float(aggregates.tokens_24h),
|
|
695
|
+
cost_24h_cents=aggregates.cost_24h_cents,
|
|
696
|
+
carbon_24h_grams=aggregates.carbon_24h_grams,
|
|
697
|
+
energy_24h_kwh=aggregates.energy_24h_kwh,
|
|
698
|
+
error_rate_percent=error_rate,
|
|
699
|
+
avg_thought_depth=avg_thought_depth,
|
|
700
|
+
queue_saturation=queue_saturation,
|
|
701
|
+
circuit_breaker=circuit_breaker,
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
# =============================================================================
|
|
706
|
+
# QUERY_METRICS HELPERS (CC 22 → 6 reduction)
|
|
707
|
+
# =============================================================================
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def calculate_query_time_window(start_time: Optional[datetime], end_time: Optional[datetime], now: datetime) -> int:
|
|
711
|
+
"""
|
|
712
|
+
Calculate hours for query time window.
|
|
713
|
+
|
|
714
|
+
Args:
|
|
715
|
+
start_time: Optional start of time range
|
|
716
|
+
end_time: Optional end of time range
|
|
717
|
+
now: Current time
|
|
718
|
+
|
|
719
|
+
Returns:
|
|
720
|
+
Number of hours for the query window (default 24)
|
|
721
|
+
"""
|
|
722
|
+
if start_time and end_time:
|
|
723
|
+
return int((end_time - start_time).total_seconds() / 3600)
|
|
724
|
+
elif start_time:
|
|
725
|
+
return int((now - start_time).total_seconds() / 3600)
|
|
726
|
+
return 24 # Default
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
def filter_by_metric_name(data: object, metric_name: str) -> bool:
|
|
730
|
+
"""
|
|
731
|
+
Check if timeseries data matches the requested metric name.
|
|
732
|
+
|
|
733
|
+
Args:
|
|
734
|
+
data: Timeseries data point with metric_name attribute
|
|
735
|
+
metric_name: Name of metric to match
|
|
736
|
+
|
|
737
|
+
Returns:
|
|
738
|
+
True if data matches metric name
|
|
739
|
+
"""
|
|
740
|
+
return getattr(data, "metric_name", None) == metric_name
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
def filter_by_tags(data: object, tags: Optional[Dict[str, str]]) -> bool:
|
|
744
|
+
"""
|
|
745
|
+
Check if timeseries data matches all required tags.
|
|
746
|
+
|
|
747
|
+
Args:
|
|
748
|
+
data: Timeseries data point with tags or labels attribute
|
|
749
|
+
tags: Optional dictionary of tags to match
|
|
750
|
+
|
|
751
|
+
Returns:
|
|
752
|
+
True if data matches all tags (or tags is None)
|
|
753
|
+
"""
|
|
754
|
+
if not tags:
|
|
755
|
+
return True
|
|
756
|
+
|
|
757
|
+
# Check both 'tags' and 'labels' attributes
|
|
758
|
+
# Note: 'tags' may be a list, 'labels' is the dict we want for key-value filtering
|
|
759
|
+
data_tags = getattr(data, "tags", None)
|
|
760
|
+
if not isinstance(data_tags, dict):
|
|
761
|
+
data_tags = getattr(data, "labels", None)
|
|
762
|
+
if not isinstance(data_tags, dict):
|
|
763
|
+
data_tags = {}
|
|
764
|
+
|
|
765
|
+
return all(data_tags.get(k) == v for k, v in tags.items())
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
def filter_by_time_range(data: object, start_time: Optional[datetime], end_time: Optional[datetime]) -> bool:
|
|
769
|
+
"""
|
|
770
|
+
Check if timeseries data timestamp is within the specified range.
|
|
771
|
+
|
|
772
|
+
Args:
|
|
773
|
+
data: Timeseries data point with timestamp/start_time attribute
|
|
774
|
+
start_time: Optional start of time range
|
|
775
|
+
end_time: Optional end of time range
|
|
776
|
+
|
|
777
|
+
Returns:
|
|
778
|
+
True if timestamp is within range (or no range specified)
|
|
779
|
+
"""
|
|
780
|
+
# Try timestamp first, fall back to start_time (used by TSDBGraphNode)
|
|
781
|
+
timestamp = getattr(data, "timestamp", None) or getattr(data, "start_time", None)
|
|
782
|
+
if not timestamp:
|
|
783
|
+
return False
|
|
784
|
+
|
|
785
|
+
if start_time and timestamp < start_time:
|
|
786
|
+
return False
|
|
787
|
+
|
|
788
|
+
if end_time and timestamp > end_time:
|
|
789
|
+
return False
|
|
790
|
+
|
|
791
|
+
return True
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
def convert_to_metric_record(data: object) -> Optional[MetricRecord]:
|
|
795
|
+
"""
|
|
796
|
+
Convert timeseries data to typed MetricRecord.
|
|
797
|
+
|
|
798
|
+
Args:
|
|
799
|
+
data: Timeseries data point
|
|
800
|
+
|
|
801
|
+
Returns:
|
|
802
|
+
MetricRecord if data is valid, None otherwise
|
|
803
|
+
"""
|
|
804
|
+
metric_name = getattr(data, "metric_name", None)
|
|
805
|
+
value = getattr(data, "value", None)
|
|
806
|
+
# Try timestamp first, fall back to start_time (used by TSDBGraphNode)
|
|
807
|
+
timestamp = getattr(data, "timestamp", None) or getattr(data, "start_time", None)
|
|
808
|
+
|
|
809
|
+
# Validate required fields
|
|
810
|
+
if not (metric_name and value is not None and timestamp):
|
|
811
|
+
return None
|
|
812
|
+
|
|
813
|
+
# Check both 'tags' and 'labels' attributes
|
|
814
|
+
# Note: 'tags' may be a list, 'labels' is the dict we want for metadata
|
|
815
|
+
tags = getattr(data, "tags", None)
|
|
816
|
+
if not isinstance(tags, dict):
|
|
817
|
+
tags = getattr(data, "labels", None)
|
|
818
|
+
if not isinstance(tags, dict):
|
|
819
|
+
tags = {}
|
|
820
|
+
|
|
821
|
+
return MetricRecord(
|
|
822
|
+
metric_name=metric_name,
|
|
823
|
+
value=value,
|
|
824
|
+
timestamp=timestamp,
|
|
825
|
+
tags=tags,
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
# =============================================================================
|
|
830
|
+
# _TRY_COLLECT_METRICS HELPERS (CC 19 → 6 reduction)
|
|
831
|
+
# =============================================================================
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
def should_retry_metric_collection(attempt: int, max_retries: int) -> bool:
|
|
835
|
+
"""
|
|
836
|
+
Determine if metric collection should be retried.
|
|
837
|
+
|
|
838
|
+
Args:
|
|
839
|
+
attempt: Current attempt number (0-indexed)
|
|
840
|
+
max_retries: Maximum number of retries allowed
|
|
841
|
+
|
|
842
|
+
Returns:
|
|
843
|
+
True if should retry
|
|
844
|
+
"""
|
|
845
|
+
return attempt < max_retries
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
def calculate_retry_delay(attempt: int, base_delay: float = 0.1) -> float:
|
|
849
|
+
"""
|
|
850
|
+
Calculate exponential backoff delay for retry.
|
|
851
|
+
|
|
852
|
+
Args:
|
|
853
|
+
attempt: Current attempt number (0-indexed)
|
|
854
|
+
base_delay: Base delay in seconds
|
|
855
|
+
|
|
856
|
+
Returns:
|
|
857
|
+
Delay in seconds
|
|
858
|
+
"""
|
|
859
|
+
return float(base_delay * (2**attempt))
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
def validate_collected_metrics(metrics: object) -> bool:
|
|
863
|
+
"""
|
|
864
|
+
Validate that collected metrics are in expected format.
|
|
865
|
+
|
|
866
|
+
Args:
|
|
867
|
+
metrics: Metrics data to validate
|
|
868
|
+
|
|
869
|
+
Returns:
|
|
870
|
+
True if metrics are valid
|
|
871
|
+
"""
|
|
872
|
+
if metrics is None:
|
|
873
|
+
return False
|
|
874
|
+
|
|
875
|
+
# Check if it's a dictionary with expected structure
|
|
876
|
+
if isinstance(metrics, dict):
|
|
877
|
+
return True
|
|
878
|
+
|
|
879
|
+
# Check if it's an object with attributes
|
|
880
|
+
if hasattr(metrics, "__dict__"):
|
|
881
|
+
return True
|
|
882
|
+
|
|
883
|
+
return False
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
# =============================================================================
|
|
887
|
+
# COLLECT_FROM_ADAPTER_INSTANCES HELPERS (CC 19 → 6 reduction)
|
|
888
|
+
# =============================================================================
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
def extract_adapter_name(adapter: object) -> str:
|
|
892
|
+
"""
|
|
893
|
+
Extract adapter name from adapter instance.
|
|
894
|
+
|
|
895
|
+
Args:
|
|
896
|
+
adapter: Adapter instance
|
|
897
|
+
|
|
898
|
+
Returns:
|
|
899
|
+
Adapter name string
|
|
900
|
+
"""
|
|
901
|
+
if hasattr(adapter, "adapter_name"):
|
|
902
|
+
return str(adapter.adapter_name)
|
|
903
|
+
elif hasattr(adapter, "name"):
|
|
904
|
+
return str(adapter.name)
|
|
905
|
+
elif hasattr(adapter, "__class__"):
|
|
906
|
+
return adapter.__class__.__name__
|
|
907
|
+
return "unknown_adapter"
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
def is_adapter_healthy(adapter: object) -> bool:
|
|
911
|
+
"""
|
|
912
|
+
Check if adapter is in healthy state for metrics collection.
|
|
913
|
+
|
|
914
|
+
Args:
|
|
915
|
+
adapter: Adapter instance
|
|
916
|
+
|
|
917
|
+
Returns:
|
|
918
|
+
True if adapter is healthy
|
|
919
|
+
"""
|
|
920
|
+
# Check if adapter has status attribute
|
|
921
|
+
if hasattr(adapter, "status"):
|
|
922
|
+
status = adapter.status
|
|
923
|
+
if hasattr(status, "value"):
|
|
924
|
+
return bool(status.value == "running")
|
|
925
|
+
return str(status).lower() == "running"
|
|
926
|
+
|
|
927
|
+
# If no status, assume healthy
|
|
928
|
+
return True
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
async def collect_metrics_from_single_adapter(adapter: object) -> Optional[Dict[str, float]]:
|
|
932
|
+
"""
|
|
933
|
+
Collect metrics from a single adapter instance.
|
|
934
|
+
|
|
935
|
+
Args:
|
|
936
|
+
adapter: Adapter instance
|
|
937
|
+
|
|
938
|
+
Returns:
|
|
939
|
+
Metrics dictionary or None if collection failed
|
|
940
|
+
"""
|
|
941
|
+
try:
|
|
942
|
+
if hasattr(adapter, "get_metrics"):
|
|
943
|
+
metrics = await adapter.get_metrics()
|
|
944
|
+
return metrics if isinstance(metrics, dict) else None
|
|
945
|
+
return None
|
|
946
|
+
except Exception:
|
|
947
|
+
return None
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
def aggregate_adapter_metrics(collected_metrics: List[Dict[str, float]]) -> Dict[str, float]:
|
|
951
|
+
"""
|
|
952
|
+
Aggregate metrics from multiple adapters.
|
|
953
|
+
|
|
954
|
+
Args:
|
|
955
|
+
collected_metrics: List of metrics dictionaries
|
|
956
|
+
|
|
957
|
+
Returns:
|
|
958
|
+
Aggregated metrics dictionary
|
|
959
|
+
"""
|
|
960
|
+
aggregated: Dict[str, float] = {}
|
|
961
|
+
|
|
962
|
+
for metrics in collected_metrics:
|
|
963
|
+
if not metrics:
|
|
964
|
+
continue
|
|
965
|
+
|
|
966
|
+
for key, value in metrics.items():
|
|
967
|
+
if key not in aggregated:
|
|
968
|
+
aggregated[key] = value
|
|
969
|
+
elif isinstance(value, (int, float)) and isinstance(aggregated[key], (int, float)):
|
|
970
|
+
# Sum numeric values
|
|
971
|
+
aggregated[key] = aggregated[key] + value
|
|
972
|
+
|
|
973
|
+
return aggregated
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
# =============================================================================
|
|
977
|
+
# _GENERATE_SEMANTIC_SERVICE_NAME HELPERS (CC 16 → 6 reduction)
|
|
978
|
+
# =============================================================================
|
|
979
|
+
|
|
980
|
+
|
|
981
|
+
# Service name mapping table
|
|
982
|
+
SERVICE_NAME_MAPPING: Dict[str, str] = {
|
|
983
|
+
"memory_service": "Memory Service",
|
|
984
|
+
"config_service": "Configuration Service",
|
|
985
|
+
"telemetry_service": "Telemetry Service",
|
|
986
|
+
"audit_service": "Audit Service",
|
|
987
|
+
"incident_service": "Incident Management Service",
|
|
988
|
+
"tsdb_consolidation_service": "Time-Series Database Consolidation Service",
|
|
989
|
+
"authentication_service": "Authentication Service",
|
|
990
|
+
"resource_monitor": "Resource Monitor",
|
|
991
|
+
"database_maintenance": "Database Maintenance",
|
|
992
|
+
"secrets_service": "Secrets Service",
|
|
993
|
+
"initialization_service": "Initialization Service",
|
|
994
|
+
"shutdown_service": "Shutdown Service",
|
|
995
|
+
"time_service": "Time Service",
|
|
996
|
+
"task_scheduler": "Task Scheduler",
|
|
997
|
+
"wise_authority": "Wise Authority",
|
|
998
|
+
"adaptive_filter": "Adaptive Filter",
|
|
999
|
+
"visibility_service": "Visibility Service",
|
|
1000
|
+
"consent_service": "Consent Service",
|
|
1001
|
+
"self_observation": "Self-Observation Service",
|
|
1002
|
+
"llm_service": "LLM Service",
|
|
1003
|
+
"runtime_control": "Runtime Control",
|
|
1004
|
+
"secrets_tool": "Secrets Tool",
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
|
|
1008
|
+
def generate_semantic_service_name(service_name: str) -> str:
|
|
1009
|
+
"""
|
|
1010
|
+
Generate human-readable semantic name for a service.
|
|
1011
|
+
|
|
1012
|
+
Uses a lookup table approach for better maintainability and lower complexity.
|
|
1013
|
+
|
|
1014
|
+
Args:
|
|
1015
|
+
service_name: Technical service name
|
|
1016
|
+
|
|
1017
|
+
Returns:
|
|
1018
|
+
Human-readable service name
|
|
1019
|
+
"""
|
|
1020
|
+
# Direct lookup in mapping table
|
|
1021
|
+
if service_name in SERVICE_NAME_MAPPING:
|
|
1022
|
+
return SERVICE_NAME_MAPPING[service_name]
|
|
1023
|
+
|
|
1024
|
+
# Fallback: Convert snake_case to Title Case
|
|
1025
|
+
return service_name.replace("_", " ").title()
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
def get_service_category(service_name: str) -> str:
|
|
1029
|
+
"""
|
|
1030
|
+
Categorize service by type.
|
|
1031
|
+
|
|
1032
|
+
Args:
|
|
1033
|
+
service_name: Service name
|
|
1034
|
+
|
|
1035
|
+
Returns:
|
|
1036
|
+
Service category
|
|
1037
|
+
"""
|
|
1038
|
+
graph_services = {"memory", "config", "telemetry", "audit", "incident", "tsdb"}
|
|
1039
|
+
infrastructure = {"authentication", "resource", "database", "secrets"}
|
|
1040
|
+
lifecycle = {"initialization", "shutdown", "time", "task"}
|
|
1041
|
+
governance = {"wise", "adaptive", "visibility", "consent", "observation"}
|
|
1042
|
+
|
|
1043
|
+
name_lower = service_name.lower()
|
|
1044
|
+
|
|
1045
|
+
if any(svc in name_lower for svc in graph_services):
|
|
1046
|
+
return "graph"
|
|
1047
|
+
elif any(svc in name_lower for svc in infrastructure):
|
|
1048
|
+
return "infrastructure"
|
|
1049
|
+
elif any(svc in name_lower for svc in lifecycle):
|
|
1050
|
+
return "lifecycle"
|
|
1051
|
+
elif any(svc in name_lower for svc in governance):
|
|
1052
|
+
return "governance"
|
|
1053
|
+
else:
|
|
1054
|
+
return "runtime"
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
# ============================================================================
|
|
1058
|
+
# CONTINUITY SUMMARY HELPERS
|
|
1059
|
+
# ============================================================================
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
def _extract_timestamp_from_node_id(node: Any, prefix: str) -> Optional[datetime]:
|
|
1063
|
+
"""Extract timestamp from lifecycle node ID.
|
|
1064
|
+
|
|
1065
|
+
Args:
|
|
1066
|
+
node: Graph node with lifecycle event
|
|
1067
|
+
prefix: Node ID prefix ('startup_' or 'shutdown_')
|
|
1068
|
+
|
|
1069
|
+
Returns:
|
|
1070
|
+
Datetime if successfully extracted, None otherwise
|
|
1071
|
+
"""
|
|
1072
|
+
if not hasattr(node, "id") or not node.id.startswith(prefix):
|
|
1073
|
+
return None
|
|
1074
|
+
|
|
1075
|
+
ts_str = node.id.replace(prefix, "")
|
|
1076
|
+
try:
|
|
1077
|
+
return datetime.fromisoformat(ts_str)
|
|
1078
|
+
except (ValueError, TypeError):
|
|
1079
|
+
return None
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
def _extract_shutdown_reason_from_node(node: Any) -> Optional[str]:
|
|
1083
|
+
"""Extract shutdown reason from shutdown node attributes.
|
|
1084
|
+
|
|
1085
|
+
Args:
|
|
1086
|
+
node: Shutdown graph node
|
|
1087
|
+
|
|
1088
|
+
Returns:
|
|
1089
|
+
Shutdown reason string if found, None otherwise
|
|
1090
|
+
"""
|
|
1091
|
+
if not hasattr(node, "attributes"):
|
|
1092
|
+
return None
|
|
1093
|
+
|
|
1094
|
+
attrs = node.attributes
|
|
1095
|
+
|
|
1096
|
+
# Handle both dict (NodeAttributes) and object (GraphNodeAttributes) forms
|
|
1097
|
+
if isinstance(attrs, dict):
|
|
1098
|
+
reason = attrs.get("reason")
|
|
1099
|
+
return str(reason) if reason is not None else None
|
|
1100
|
+
elif hasattr(attrs, "reason"):
|
|
1101
|
+
reason = attrs.reason
|
|
1102
|
+
return str(reason) if reason is not None else None
|
|
1103
|
+
|
|
1104
|
+
return None
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
def _extract_shutdown_consent_from_node(node: Any) -> Optional[str]:
|
|
1108
|
+
"""Extract shutdown consent status from shutdown node attributes.
|
|
1109
|
+
|
|
1110
|
+
Args:
|
|
1111
|
+
node: Shutdown graph node
|
|
1112
|
+
|
|
1113
|
+
Returns:
|
|
1114
|
+
Consent status string ('accepted', 'rejected', or 'manual') if found, None otherwise
|
|
1115
|
+
"""
|
|
1116
|
+
if not hasattr(node, "attributes"):
|
|
1117
|
+
return None
|
|
1118
|
+
|
|
1119
|
+
attrs = node.attributes
|
|
1120
|
+
|
|
1121
|
+
# Handle both dict (NodeAttributes) and object (GraphNodeAttributes) forms
|
|
1122
|
+
if isinstance(attrs, dict):
|
|
1123
|
+
consent = attrs.get("consent_status")
|
|
1124
|
+
return str(consent) if consent is not None else None
|
|
1125
|
+
elif hasattr(attrs, "consent_status"):
|
|
1126
|
+
consent = attrs.consent_status
|
|
1127
|
+
return str(consent) if consent is not None else None
|
|
1128
|
+
|
|
1129
|
+
return None
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
def _extract_timestamps_from_nodes(nodes: List[Any], prefix: str) -> List[datetime]:
|
|
1133
|
+
"""Extract all valid timestamps from lifecycle nodes.
|
|
1134
|
+
|
|
1135
|
+
Args:
|
|
1136
|
+
nodes: List of graph nodes
|
|
1137
|
+
prefix: Node ID prefix to match
|
|
1138
|
+
|
|
1139
|
+
Returns:
|
|
1140
|
+
List of extracted timestamps
|
|
1141
|
+
"""
|
|
1142
|
+
timestamps = []
|
|
1143
|
+
for node in nodes:
|
|
1144
|
+
ts = _extract_timestamp_from_node_id(node, prefix)
|
|
1145
|
+
if ts:
|
|
1146
|
+
timestamps.append(ts)
|
|
1147
|
+
return timestamps
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
def _merge_and_sort_events(
|
|
1151
|
+
startup_timestamps: List[datetime], shutdown_timestamps: List[datetime]
|
|
1152
|
+
) -> List[Tuple[str, datetime]]:
|
|
1153
|
+
"""Merge startup/shutdown timestamps into sorted event list.
|
|
1154
|
+
|
|
1155
|
+
Args:
|
|
1156
|
+
startup_timestamps: List of startup times
|
|
1157
|
+
shutdown_timestamps: List of shutdown times
|
|
1158
|
+
|
|
1159
|
+
Returns:
|
|
1160
|
+
Sorted list of (event_type, timestamp) tuples
|
|
1161
|
+
"""
|
|
1162
|
+
all_events = []
|
|
1163
|
+
for ts in startup_timestamps:
|
|
1164
|
+
all_events.append(("startup", ts))
|
|
1165
|
+
for ts in shutdown_timestamps:
|
|
1166
|
+
all_events.append(("shutdown", ts))
|
|
1167
|
+
all_events.sort(key=lambda x: x[1])
|
|
1168
|
+
return all_events
|
|
1169
|
+
|
|
1170
|
+
|
|
1171
|
+
def _infer_missing_startup(
|
|
1172
|
+
last_shutdown_ts: Optional[datetime], current_shutdown_ts: datetime
|
|
1173
|
+
) -> Tuple[datetime, float]:
|
|
1174
|
+
"""Infer startup time for shutdown without matching startup.
|
|
1175
|
+
|
|
1176
|
+
Args:
|
|
1177
|
+
last_shutdown_ts: Previous shutdown timestamp (None if first shutdown)
|
|
1178
|
+
current_shutdown_ts: Current shutdown timestamp
|
|
1179
|
+
|
|
1180
|
+
Returns:
|
|
1181
|
+
Tuple of (inferred_startup_time, offline_seconds_to_add)
|
|
1182
|
+
"""
|
|
1183
|
+
from datetime import timedelta
|
|
1184
|
+
|
|
1185
|
+
if last_shutdown_ts is None:
|
|
1186
|
+
# First shutdown: assume startup 1 minute BEFORE
|
|
1187
|
+
inferred_startup = current_shutdown_ts - timedelta(minutes=1)
|
|
1188
|
+
logger.debug(
|
|
1189
|
+
f"First shutdown at {current_shutdown_ts} without startup, "
|
|
1190
|
+
f"inferring startup 1 minute before at {inferred_startup}"
|
|
1191
|
+
)
|
|
1192
|
+
return inferred_startup, 0.0
|
|
1193
|
+
else:
|
|
1194
|
+
# Subsequent shutdown: assume startup 1 minute AFTER previous shutdown
|
|
1195
|
+
inferred_startup = last_shutdown_ts + timedelta(minutes=1)
|
|
1196
|
+
logger.debug(
|
|
1197
|
+
f"Shutdown at {current_shutdown_ts} without startup after previous shutdown at {last_shutdown_ts}, "
|
|
1198
|
+
f"inferring startup 1 minute after at {inferred_startup}"
|
|
1199
|
+
)
|
|
1200
|
+
return inferred_startup, 60.0 # 1 minute downtime
|
|
1201
|
+
|
|
1202
|
+
|
|
1203
|
+
def _calculate_online_offline_durations(all_events: List[Tuple[str, datetime]]) -> Tuple[float, float]:
|
|
1204
|
+
"""Calculate total online/offline durations from lifecycle events.
|
|
1205
|
+
|
|
1206
|
+
Args:
|
|
1207
|
+
all_events: Sorted list of (event_type, timestamp) tuples
|
|
1208
|
+
|
|
1209
|
+
Returns:
|
|
1210
|
+
Tuple of (total_online_seconds, total_offline_seconds)
|
|
1211
|
+
"""
|
|
1212
|
+
total_online = 0.0
|
|
1213
|
+
total_offline = 0.0
|
|
1214
|
+
current_session_start = None
|
|
1215
|
+
last_shutdown = None
|
|
1216
|
+
|
|
1217
|
+
for i, (event_type, ts) in enumerate(all_events):
|
|
1218
|
+
if event_type == "startup":
|
|
1219
|
+
current_session_start = ts
|
|
1220
|
+
|
|
1221
|
+
elif event_type == "shutdown":
|
|
1222
|
+
# Infer missing startup if needed
|
|
1223
|
+
if not current_session_start:
|
|
1224
|
+
current_session_start, offline_to_add = _infer_missing_startup(last_shutdown, ts)
|
|
1225
|
+
total_offline += offline_to_add
|
|
1226
|
+
|
|
1227
|
+
# Calculate session duration
|
|
1228
|
+
session_duration = (ts - current_session_start).total_seconds()
|
|
1229
|
+
total_online += session_duration
|
|
1230
|
+
|
|
1231
|
+
# Calculate offline time to next startup
|
|
1232
|
+
if i + 1 < len(all_events) and all_events[i + 1][0] == "startup":
|
|
1233
|
+
next_startup = all_events[i + 1][1]
|
|
1234
|
+
offline_duration = (next_startup - ts).total_seconds()
|
|
1235
|
+
total_offline += offline_duration
|
|
1236
|
+
|
|
1237
|
+
last_shutdown = ts
|
|
1238
|
+
current_session_start = None
|
|
1239
|
+
|
|
1240
|
+
return total_online, total_offline
|
|
1241
|
+
|
|
1242
|
+
|
|
1243
|
+
async def _fetch_lifecycle_nodes(memory_service: Any) -> Tuple[List[Any], List[Any]]:
|
|
1244
|
+
"""Fetch startup and shutdown nodes from memory.
|
|
1245
|
+
|
|
1246
|
+
Args:
|
|
1247
|
+
memory_service: Memory service for queries
|
|
1248
|
+
|
|
1249
|
+
Returns:
|
|
1250
|
+
Tuple of (startup_nodes, shutdown_nodes)
|
|
1251
|
+
"""
|
|
1252
|
+
from ciris_engine.schemas.services.graph.memory import MemorySearchFilter
|
|
1253
|
+
from ciris_engine.schemas.services.graph_core import GraphScope
|
|
1254
|
+
|
|
1255
|
+
startup_filter = MemorySearchFilter(scope=GraphScope.IDENTITY.value, node_type="agent", limit=1000)
|
|
1256
|
+
startup_nodes = await memory_service.search(query="startup", filters=startup_filter)
|
|
1257
|
+
|
|
1258
|
+
shutdown_filter = MemorySearchFilter(scope=GraphScope.IDENTITY.value, node_type="agent", limit=1000)
|
|
1259
|
+
shutdown_nodes = await memory_service.search(query="shutdown", filters=shutdown_filter)
|
|
1260
|
+
|
|
1261
|
+
return startup_nodes, shutdown_nodes
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
async def build_continuity_summary_from_memory(
|
|
1265
|
+
memory_service: Optional[Any], time_service: Any, start_time: Optional[datetime]
|
|
1266
|
+
) -> Optional[ContinuitySummary]:
|
|
1267
|
+
"""Build continuity summary from startup/shutdown memory nodes.
|
|
1268
|
+
|
|
1269
|
+
Args:
|
|
1270
|
+
memory_service: Memory service to query for lifecycle events
|
|
1271
|
+
time_service: Time service for current time
|
|
1272
|
+
start_time: Service start time for current session
|
|
1273
|
+
|
|
1274
|
+
Returns:
|
|
1275
|
+
ContinuitySummary if memory service available, None otherwise
|
|
1276
|
+
"""
|
|
1277
|
+
if not memory_service:
|
|
1278
|
+
return None
|
|
1279
|
+
|
|
1280
|
+
try:
|
|
1281
|
+
now = time_service.now() if time_service else datetime.now(timezone.utc)
|
|
1282
|
+
|
|
1283
|
+
# Fetch lifecycle nodes
|
|
1284
|
+
startup_nodes, shutdown_nodes = await _fetch_lifecycle_nodes(memory_service)
|
|
1285
|
+
|
|
1286
|
+
# Extract timestamps
|
|
1287
|
+
startup_timestamps = _extract_timestamps_from_nodes(startup_nodes, "startup_")
|
|
1288
|
+
shutdown_timestamps = _extract_timestamps_from_nodes(shutdown_nodes, "shutdown_")
|
|
1289
|
+
|
|
1290
|
+
# Calculate basic metrics
|
|
1291
|
+
first_startup = min(startup_timestamps) if startup_timestamps else None
|
|
1292
|
+
last_shutdown_ts = max(shutdown_timestamps) if shutdown_timestamps else None
|
|
1293
|
+
|
|
1294
|
+
# Extract last shutdown reason and consent status from the most recent shutdown node
|
|
1295
|
+
last_shutdown_reason = None
|
|
1296
|
+
last_shutdown_consent = None
|
|
1297
|
+
if shutdown_nodes and last_shutdown_ts:
|
|
1298
|
+
# Find the shutdown node with the matching timestamp
|
|
1299
|
+
for node in shutdown_nodes:
|
|
1300
|
+
node_ts = _extract_timestamp_from_node_id(node, "shutdown_")
|
|
1301
|
+
if node_ts == last_shutdown_ts:
|
|
1302
|
+
last_shutdown_reason = _extract_shutdown_reason_from_node(node)
|
|
1303
|
+
last_shutdown_consent = _extract_shutdown_consent_from_node(node)
|
|
1304
|
+
break
|
|
1305
|
+
|
|
1306
|
+
# Merge and calculate durations
|
|
1307
|
+
all_events = _merge_and_sort_events(startup_timestamps, shutdown_timestamps)
|
|
1308
|
+
total_online, total_offline = _calculate_online_offline_durations(all_events)
|
|
1309
|
+
|
|
1310
|
+
# Add current session if online
|
|
1311
|
+
current_session_duration = 0.0
|
|
1312
|
+
if start_time:
|
|
1313
|
+
current_session_duration = (now - start_time).total_seconds()
|
|
1314
|
+
total_online += current_session_duration
|
|
1315
|
+
|
|
1316
|
+
# Calculate averages
|
|
1317
|
+
total_shutdowns = len(shutdown_timestamps)
|
|
1318
|
+
avg_online = total_online / (total_shutdowns + 1) if total_shutdowns >= 0 else 0.0
|
|
1319
|
+
avg_offline = total_offline / total_shutdowns if total_shutdowns > 0 else 0.0
|
|
1320
|
+
|
|
1321
|
+
return ContinuitySummary(
|
|
1322
|
+
first_startup=first_startup,
|
|
1323
|
+
total_time_online_seconds=total_online,
|
|
1324
|
+
total_time_offline_seconds=total_offline,
|
|
1325
|
+
total_shutdowns=total_shutdowns,
|
|
1326
|
+
average_time_online_seconds=avg_online,
|
|
1327
|
+
average_time_offline_seconds=avg_offline,
|
|
1328
|
+
current_session_start=start_time,
|
|
1329
|
+
current_session_duration_seconds=current_session_duration,
|
|
1330
|
+
last_shutdown=last_shutdown_ts,
|
|
1331
|
+
last_shutdown_reason=last_shutdown_reason,
|
|
1332
|
+
last_shutdown_consent=last_shutdown_consent,
|
|
1333
|
+
)
|
|
1334
|
+
|
|
1335
|
+
except Exception as e:
|
|
1336
|
+
logger.warning(f"Failed to build continuity summary: {e}")
|
|
1337
|
+
return None
|