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,1043 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from typing import TYPE_CHECKING, Any, List, Optional
|
|
4
|
+
|
|
5
|
+
from ciris_engine.logic.persistence.db import get_db_connection
|
|
6
|
+
from ciris_engine.logic.persistence.db.dialect import get_adapter
|
|
7
|
+
from ciris_engine.logic.persistence.utils import map_row_to_task
|
|
8
|
+
from ciris_engine.protocols.services.graph.audit import AuditServiceProtocol
|
|
9
|
+
from ciris_engine.protocols.services.lifecycle.time import TimeServiceProtocol
|
|
10
|
+
from ciris_engine.schemas.runtime.enums import HandlerActionType, TaskStatus, ThoughtStatus
|
|
11
|
+
from ciris_engine.schemas.runtime.models import Task, TaskContext
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from ciris_engine.protocols.services.infrastructure.authentication import AuthenticationServiceProtocol
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_task_by_id_any_occurrence(task_id: str, db_path: Optional[str] = None) -> Optional[Task]:
|
|
20
|
+
"""
|
|
21
|
+
Get a task by ID without filtering by occurrence_id.
|
|
22
|
+
|
|
23
|
+
This is needed for task completion handlers that need to read the task's
|
|
24
|
+
actual occurrence_id before updating it. Unlike get_task_by_id() which filters
|
|
25
|
+
by occurrence_id, this function retrieves the task regardless of occurrence.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
task_id: The task ID to look up
|
|
29
|
+
db_path: Optional database path (defaults to main database)
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
The Task object, or None if task not found
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
>>> task = get_task_by_id_any_occurrence("SHUTDOWN_SHARED_20251031")
|
|
36
|
+
>>> task.agent_occurrence_id
|
|
37
|
+
'__shared__'
|
|
38
|
+
"""
|
|
39
|
+
sql = "SELECT * FROM tasks WHERE task_id = ? LIMIT 1"
|
|
40
|
+
try:
|
|
41
|
+
with get_db_connection(db_path) as conn:
|
|
42
|
+
cursor = conn.cursor()
|
|
43
|
+
cursor.execute(sql, (task_id,))
|
|
44
|
+
row = cursor.fetchone()
|
|
45
|
+
if row:
|
|
46
|
+
return map_row_to_task(row)
|
|
47
|
+
logger.warning(f"Task {task_id} not found (any occurrence)")
|
|
48
|
+
return None
|
|
49
|
+
except Exception as e:
|
|
50
|
+
logger.exception(f"Failed to get task {task_id} (any occurrence): {e}")
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_task_occurrence_id_for_update(task_id: str, db_path: Optional[str] = None) -> Optional[str]:
|
|
55
|
+
"""
|
|
56
|
+
Get the correct occurrence_id for updating a task's status.
|
|
57
|
+
|
|
58
|
+
This handles 6 scenarios robustly:
|
|
59
|
+
1. SQLite single agent (default) - returns "default"
|
|
60
|
+
2. SQLite multi-occurrence claiming agent - returns actual occurrence_id
|
|
61
|
+
3. SQLite multi-occurrence non-claimant - returns "__shared__"
|
|
62
|
+
4. PostgreSQL single agent (default) - returns "default"
|
|
63
|
+
5. PostgreSQL multi-occurrence claiming agent - returns actual occurrence_id
|
|
64
|
+
6. PostgreSQL multi-occurrence non-claimant - returns "__shared__"
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
task_id: The task ID to look up
|
|
68
|
+
db_path: Optional database path (defaults to main database)
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
The occurrence_id to use for UPDATE queries, or None if task not found
|
|
72
|
+
|
|
73
|
+
Examples:
|
|
74
|
+
>>> get_task_occurrence_id_for_update("SHUTDOWN_SHARED_20251031")
|
|
75
|
+
'__shared__'
|
|
76
|
+
>>> get_task_occurrence_id_for_update("regular-task-123")
|
|
77
|
+
'default'
|
|
78
|
+
"""
|
|
79
|
+
sql = "SELECT agent_occurrence_id FROM tasks WHERE task_id = ? LIMIT 1"
|
|
80
|
+
try:
|
|
81
|
+
with get_db_connection(db_path) as conn:
|
|
82
|
+
cursor = conn.cursor()
|
|
83
|
+
cursor.execute(sql, (task_id,))
|
|
84
|
+
row = cursor.fetchone()
|
|
85
|
+
if row:
|
|
86
|
+
return str(row[0])
|
|
87
|
+
logger.warning(f"Task {task_id} not found when looking up occurrence_id for update")
|
|
88
|
+
return None
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.exception(f"Failed to get occurrence_id for task {task_id}: {e}")
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_tasks_by_status(
|
|
95
|
+
status: TaskStatus, occurrence_id: str = "default", db_path: Optional[str] = None
|
|
96
|
+
) -> List[Task]:
|
|
97
|
+
"""Returns all tasks with the given status and occurrence from the tasks table as Task objects."""
|
|
98
|
+
if not isinstance(status, TaskStatus):
|
|
99
|
+
raise TypeError(f"Expected TaskStatus enum, got {type(status)}: {status}")
|
|
100
|
+
status_val = status.value
|
|
101
|
+
sql = "SELECT * FROM tasks WHERE status = ? AND agent_occurrence_id = ? ORDER BY created_at ASC"
|
|
102
|
+
tasks_list: List[Any] = []
|
|
103
|
+
try:
|
|
104
|
+
with get_db_connection(db_path) as conn:
|
|
105
|
+
cursor = conn.cursor()
|
|
106
|
+
cursor.execute(sql, (status_val, occurrence_id))
|
|
107
|
+
rows = cursor.fetchall()
|
|
108
|
+
for row in rows:
|
|
109
|
+
tasks_list.append(map_row_to_task(row))
|
|
110
|
+
except Exception as e:
|
|
111
|
+
logger.exception(f"Failed to get tasks with status {status_val} for occurrence {occurrence_id}: {e}")
|
|
112
|
+
return tasks_list
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def get_all_tasks(occurrence_id: str = "default", db_path: Optional[str] = None) -> List[Task]:
|
|
116
|
+
sql = "SELECT * FROM tasks WHERE agent_occurrence_id = ? ORDER BY created_at ASC"
|
|
117
|
+
tasks_list: List[Any] = []
|
|
118
|
+
try:
|
|
119
|
+
with get_db_connection(db_path) as conn:
|
|
120
|
+
cursor = conn.cursor()
|
|
121
|
+
cursor.execute(sql, (occurrence_id,))
|
|
122
|
+
rows = cursor.fetchall()
|
|
123
|
+
for row in rows:
|
|
124
|
+
tasks_list.append(map_row_to_task(row))
|
|
125
|
+
except Exception as e:
|
|
126
|
+
logger.exception(f"Failed to get all tasks for occurrence {occurrence_id}: {e}")
|
|
127
|
+
return tasks_list
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _is_correlation_id_constraint_violation(error_msg: str) -> bool:
|
|
131
|
+
"""
|
|
132
|
+
Check if error message indicates a unique constraint violation on correlation_id.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
error_msg: Lowercase error message from database exception
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
True if this is a correlation_id constraint violation
|
|
139
|
+
"""
|
|
140
|
+
return "unique constraint" in error_msg and ("correlation" in error_msg or "json_extract" in error_msg)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _get_correlation_id_from_task(task: Task) -> Optional[str]:
|
|
144
|
+
"""
|
|
145
|
+
Extract correlation_id from task context if available.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
task: Task object to extract correlation_id from
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
correlation_id if present, None otherwise
|
|
152
|
+
"""
|
|
153
|
+
if not task.context:
|
|
154
|
+
return None
|
|
155
|
+
return getattr(task.context, "correlation_id", None)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _handle_duplicate_task(task: Task, db_path: Optional[str]) -> str:
|
|
159
|
+
"""
|
|
160
|
+
Handle duplicate task detection by returning existing task_id.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
task: Task that triggered duplicate constraint
|
|
164
|
+
db_path: Optional database path
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Existing task_id if found, otherwise the attempted task_id
|
|
168
|
+
"""
|
|
169
|
+
correlation_id = _get_correlation_id_from_task(task)
|
|
170
|
+
logger.info(
|
|
171
|
+
f"Task with correlation_id={correlation_id} already exists for occurrence {task.agent_occurrence_id}, "
|
|
172
|
+
"skipping duplicate (race condition prevented)"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Treat empty string as None
|
|
176
|
+
if not correlation_id:
|
|
177
|
+
return task.task_id
|
|
178
|
+
|
|
179
|
+
existing_task = get_task_by_correlation_id(correlation_id, task.agent_occurrence_id, db_path)
|
|
180
|
+
if existing_task:
|
|
181
|
+
return existing_task.task_id
|
|
182
|
+
|
|
183
|
+
return task.task_id
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def add_task(task: Task, db_path: Optional[str] = None) -> str:
|
|
187
|
+
task_dict = task.model_dump(mode="json")
|
|
188
|
+
|
|
189
|
+
# Serialize images for storage
|
|
190
|
+
images_data = task_dict.get("images", [])
|
|
191
|
+
images_json = json.dumps(images_data) if images_data else None
|
|
192
|
+
|
|
193
|
+
sql = """
|
|
194
|
+
INSERT INTO tasks (task_id, channel_id, agent_occurrence_id, description, status, priority,
|
|
195
|
+
created_at, updated_at, parent_task_id, context_json, outcome_json,
|
|
196
|
+
signed_by, signature, signed_at, updated_info_available, updated_info_content,
|
|
197
|
+
images_json)
|
|
198
|
+
VALUES (:task_id, :channel_id, :agent_occurrence_id, :description, :status, :priority,
|
|
199
|
+
:created_at, :updated_at, :parent_task_id, :context, :outcome,
|
|
200
|
+
:signed_by, :signature, :signed_at, :updated_info_available, :updated_info_content,
|
|
201
|
+
:images)
|
|
202
|
+
"""
|
|
203
|
+
params = {
|
|
204
|
+
**task_dict,
|
|
205
|
+
"status": task.status.value,
|
|
206
|
+
"agent_occurrence_id": task.agent_occurrence_id,
|
|
207
|
+
"context": json.dumps(task_dict.get("context")) if task_dict.get("context") is not None else None,
|
|
208
|
+
"outcome": json.dumps(task_dict.get("outcome")) if task_dict.get("outcome") is not None else None,
|
|
209
|
+
"signed_by": task_dict.get("signed_by"),
|
|
210
|
+
"signature": task_dict.get("signature"),
|
|
211
|
+
"signed_at": task_dict.get("signed_at"),
|
|
212
|
+
"updated_info_available": 1 if task_dict.get("updated_info_available") else 0,
|
|
213
|
+
"updated_info_content": task_dict.get("updated_info_content"),
|
|
214
|
+
"images": images_json,
|
|
215
|
+
}
|
|
216
|
+
try:
|
|
217
|
+
with get_db_connection(db_path) as conn:
|
|
218
|
+
conn.execute(sql, params)
|
|
219
|
+
conn.commit()
|
|
220
|
+
image_count = len(images_data) if images_data else 0
|
|
221
|
+
if image_count > 0:
|
|
222
|
+
logger.info(
|
|
223
|
+
f"Added task ID {task.task_id} (occurrence: {task.agent_occurrence_id}) with {image_count} images."
|
|
224
|
+
)
|
|
225
|
+
else:
|
|
226
|
+
logger.info(f"Added task ID {task.task_id} (occurrence: {task.agent_occurrence_id}) to database.")
|
|
227
|
+
return task.task_id
|
|
228
|
+
except Exception as e:
|
|
229
|
+
error_msg = str(e).lower()
|
|
230
|
+
if _is_correlation_id_constraint_violation(error_msg):
|
|
231
|
+
return _handle_duplicate_task(task, db_path)
|
|
232
|
+
logger.exception(f"Failed to add task {task.task_id}: {e}")
|
|
233
|
+
raise
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def get_task_by_id(task_id: str, occurrence_id: str = "default", db_path: Optional[str] = None) -> Optional[Task]:
|
|
237
|
+
sql = "SELECT * FROM tasks WHERE task_id = ? AND agent_occurrence_id = ?"
|
|
238
|
+
try:
|
|
239
|
+
with get_db_connection(db_path) as conn:
|
|
240
|
+
cursor = conn.cursor()
|
|
241
|
+
cursor.execute(sql, (task_id, occurrence_id))
|
|
242
|
+
row = cursor.fetchone()
|
|
243
|
+
if row:
|
|
244
|
+
return map_row_to_task(row)
|
|
245
|
+
return None
|
|
246
|
+
except Exception as e:
|
|
247
|
+
logger.exception(f"Failed to get task {task_id} for occurrence {occurrence_id}: {e}")
|
|
248
|
+
return None
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def update_task_status(
|
|
252
|
+
task_id: str,
|
|
253
|
+
new_status: TaskStatus,
|
|
254
|
+
occurrence_id: str,
|
|
255
|
+
time_service: TimeServiceProtocol,
|
|
256
|
+
db_path: Optional[str] = None,
|
|
257
|
+
) -> bool:
|
|
258
|
+
sql = "UPDATE tasks SET status = ?, updated_at = ? WHERE task_id = ? AND agent_occurrence_id = ?"
|
|
259
|
+
params = (new_status.value, time_service.now_iso(), task_id, occurrence_id)
|
|
260
|
+
try:
|
|
261
|
+
with get_db_connection(db_path) as conn:
|
|
262
|
+
cursor = conn.execute(sql, params)
|
|
263
|
+
conn.commit()
|
|
264
|
+
if cursor.rowcount > 0:
|
|
265
|
+
logger.info(f"Updated status of task ID {task_id} to {new_status.value}.")
|
|
266
|
+
return True
|
|
267
|
+
logger.warning(f"Task ID {task_id} not found for status update in occurrence {occurrence_id}.")
|
|
268
|
+
return False
|
|
269
|
+
except Exception as e:
|
|
270
|
+
logger.exception(f"Failed to update task status for {task_id}: {e}")
|
|
271
|
+
return False
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def transfer_task_ownership(
|
|
275
|
+
task_id: str,
|
|
276
|
+
from_occurrence_id: str,
|
|
277
|
+
to_occurrence_id: str,
|
|
278
|
+
time_service: TimeServiceProtocol,
|
|
279
|
+
audit_service: AuditServiceProtocol,
|
|
280
|
+
db_path: Optional[str] = None,
|
|
281
|
+
) -> bool:
|
|
282
|
+
"""Transfer task ownership from one occurrence to another.
|
|
283
|
+
|
|
284
|
+
This is used when claiming shared tasks to transfer ownership from '__shared__'
|
|
285
|
+
to the claiming occurrence so seed thoughts can be processed.
|
|
286
|
+
|
|
287
|
+
Args:
|
|
288
|
+
task_id: The task ID to transfer
|
|
289
|
+
from_occurrence_id: Current occurrence ID (typically '__shared__')
|
|
290
|
+
to_occurrence_id: New occurrence ID (the claiming occurrence)
|
|
291
|
+
time_service: Time service for timestamp
|
|
292
|
+
audit_service: Audit service for logging ownership transfer events
|
|
293
|
+
db_path: Optional database path
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
True if transfer successful, False otherwise
|
|
297
|
+
"""
|
|
298
|
+
sql = "UPDATE tasks SET agent_occurrence_id = ?, updated_at = ? WHERE task_id = ? AND agent_occurrence_id = ?"
|
|
299
|
+
params = (to_occurrence_id, time_service.now_iso(), task_id, from_occurrence_id)
|
|
300
|
+
|
|
301
|
+
success = False
|
|
302
|
+
try:
|
|
303
|
+
with get_db_connection(db_path) as conn:
|
|
304
|
+
cursor = conn.execute(sql, params)
|
|
305
|
+
conn.commit()
|
|
306
|
+
if cursor.rowcount > 0:
|
|
307
|
+
logger.info(f"Transferred ownership of task {task_id} from {from_occurrence_id} to {to_occurrence_id}")
|
|
308
|
+
success = True
|
|
309
|
+
else:
|
|
310
|
+
logger.warning(f"Task {task_id} not found with occurrence {from_occurrence_id} for ownership transfer")
|
|
311
|
+
except Exception as e:
|
|
312
|
+
logger.exception(f"Failed to transfer task ownership for {task_id}: {e}")
|
|
313
|
+
success = False
|
|
314
|
+
|
|
315
|
+
# Log audit event for ownership transfer (fire and forget)
|
|
316
|
+
import asyncio
|
|
317
|
+
from typing import cast
|
|
318
|
+
|
|
319
|
+
from ciris_engine.schemas.audit.core import EventPayload
|
|
320
|
+
from ciris_engine.schemas.services.graph.audit import AuditEventData
|
|
321
|
+
|
|
322
|
+
audit_event = AuditEventData(
|
|
323
|
+
entity_id=task_id,
|
|
324
|
+
actor="system",
|
|
325
|
+
outcome="success" if success else "failed",
|
|
326
|
+
severity="info",
|
|
327
|
+
action="task_ownership_transfer",
|
|
328
|
+
resource="task",
|
|
329
|
+
metadata={
|
|
330
|
+
"task_id": task_id,
|
|
331
|
+
"from_occurrence_id": from_occurrence_id,
|
|
332
|
+
"to_occurrence_id": to_occurrence_id,
|
|
333
|
+
"task_type": "shared_coordination",
|
|
334
|
+
},
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
try:
|
|
338
|
+
# Try to get the running event loop
|
|
339
|
+
loop = asyncio.get_running_loop()
|
|
340
|
+
# Schedule the audit event as a task - cast to EventPayload for protocol compatibility
|
|
341
|
+
loop.create_task(audit_service.log_event("task_ownership_transfer", cast(EventPayload, audit_event)))
|
|
342
|
+
except RuntimeError:
|
|
343
|
+
# No event loop running - this is expected in sync contexts like tests
|
|
344
|
+
# The audit service will still track the call via the mock
|
|
345
|
+
logger.debug("No event loop running, audit logging deferred")
|
|
346
|
+
|
|
347
|
+
return success
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def update_task_context_and_signing(
|
|
351
|
+
task_id: str,
|
|
352
|
+
occurrence_id: str,
|
|
353
|
+
context: TaskContext,
|
|
354
|
+
time_service: TimeServiceProtocol,
|
|
355
|
+
signed_by: Optional[str] = None,
|
|
356
|
+
signature: Optional[str] = None,
|
|
357
|
+
signed_at: Optional[str] = None,
|
|
358
|
+
db_path: Optional[str] = None,
|
|
359
|
+
) -> bool:
|
|
360
|
+
"""Update the context and signing metadata for an existing task."""
|
|
361
|
+
|
|
362
|
+
context_json = json.dumps(context.model_dump(mode="json"))
|
|
363
|
+
sql = """
|
|
364
|
+
UPDATE tasks
|
|
365
|
+
SET context_json = ?,
|
|
366
|
+
signed_by = ?,
|
|
367
|
+
signature = ?,
|
|
368
|
+
signed_at = ?,
|
|
369
|
+
updated_at = ?
|
|
370
|
+
WHERE task_id = ? AND agent_occurrence_id = ?
|
|
371
|
+
"""
|
|
372
|
+
params = (
|
|
373
|
+
context_json,
|
|
374
|
+
signed_by,
|
|
375
|
+
signature,
|
|
376
|
+
signed_at,
|
|
377
|
+
time_service.now_iso(),
|
|
378
|
+
task_id,
|
|
379
|
+
occurrence_id,
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
try:
|
|
383
|
+
with get_db_connection(db_path) as conn:
|
|
384
|
+
cursor = conn.execute(sql, params)
|
|
385
|
+
conn.commit()
|
|
386
|
+
if cursor.rowcount > 0:
|
|
387
|
+
logger.info(
|
|
388
|
+
"Updated context and signing metadata for task %s (occurrence: %s)",
|
|
389
|
+
task_id,
|
|
390
|
+
occurrence_id,
|
|
391
|
+
)
|
|
392
|
+
return True
|
|
393
|
+
logger.warning(
|
|
394
|
+
"Task %s not found when updating context/signature for occurrence %s",
|
|
395
|
+
task_id,
|
|
396
|
+
occurrence_id,
|
|
397
|
+
)
|
|
398
|
+
return False
|
|
399
|
+
except Exception as e:
|
|
400
|
+
logger.exception(
|
|
401
|
+
"Failed to update context/signature for task %s (occurrence: %s): %s",
|
|
402
|
+
task_id,
|
|
403
|
+
occurrence_id,
|
|
404
|
+
e,
|
|
405
|
+
)
|
|
406
|
+
return False
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def clear_task_images(
|
|
410
|
+
task_id: str,
|
|
411
|
+
occurrence_id: str,
|
|
412
|
+
time_service: TimeServiceProtocol,
|
|
413
|
+
db_path: Optional[str] = None,
|
|
414
|
+
) -> bool:
|
|
415
|
+
"""Clear images from a task (for privacy/storage cleanup on completion).
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
task_id: The task ID to clear images from
|
|
419
|
+
occurrence_id: The occurrence ID for the task
|
|
420
|
+
time_service: Time service for timestamp
|
|
421
|
+
db_path: Optional database path
|
|
422
|
+
|
|
423
|
+
Returns:
|
|
424
|
+
True if images were cleared, False otherwise
|
|
425
|
+
"""
|
|
426
|
+
sql = "UPDATE tasks SET images_json = NULL, updated_at = ? WHERE task_id = ? AND agent_occurrence_id = ?"
|
|
427
|
+
params = (time_service.now_iso(), task_id, occurrence_id)
|
|
428
|
+
|
|
429
|
+
try:
|
|
430
|
+
with get_db_connection(db_path) as conn:
|
|
431
|
+
cursor = conn.execute(sql, params)
|
|
432
|
+
conn.commit()
|
|
433
|
+
if cursor.rowcount > 0:
|
|
434
|
+
logger.info(f"Cleared images from task {task_id} (occurrence: {occurrence_id})")
|
|
435
|
+
return True
|
|
436
|
+
logger.debug(f"Task {task_id} not found or no images to clear (occurrence: {occurrence_id})")
|
|
437
|
+
return False
|
|
438
|
+
except Exception as e:
|
|
439
|
+
logger.exception(f"Failed to clear images for task {task_id}: {e}")
|
|
440
|
+
return False
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def task_exists(task_id: str, db_path: Optional[str] = None) -> bool:
|
|
444
|
+
return get_task_by_id(task_id, db_path=db_path) is not None
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
async def add_system_task(
|
|
448
|
+
task: Task, auth_service: Optional["AuthenticationServiceProtocol"] = None, db_path: Optional[str] = None
|
|
449
|
+
) -> str:
|
|
450
|
+
"""Add a system task with automatic signing by the system WA.
|
|
451
|
+
|
|
452
|
+
This should be used by authorized processors (wakeup, dream, shutdown) to create
|
|
453
|
+
system tasks that are properly signed.
|
|
454
|
+
|
|
455
|
+
Args:
|
|
456
|
+
task: The task to add
|
|
457
|
+
auth_service: Authentication service for signing (optional)
|
|
458
|
+
db_path: Database path (optional)
|
|
459
|
+
|
|
460
|
+
Returns:
|
|
461
|
+
The task ID
|
|
462
|
+
"""
|
|
463
|
+
# If auth service is available, sign the task
|
|
464
|
+
if auth_service:
|
|
465
|
+
try:
|
|
466
|
+
system_wa_id = await auth_service.get_system_wa_id()
|
|
467
|
+
if system_wa_id:
|
|
468
|
+
signature, signed_at = await auth_service.sign_task(task, system_wa_id)
|
|
469
|
+
task.signed_by = system_wa_id
|
|
470
|
+
task.signature = signature
|
|
471
|
+
task.signed_at = signed_at
|
|
472
|
+
logger.info(f"Signed system task {task.task_id} with system WA {system_wa_id}")
|
|
473
|
+
else:
|
|
474
|
+
logger.warning("No system WA available for signing task")
|
|
475
|
+
except Exception as e:
|
|
476
|
+
logger.error(f"Failed to sign system task: {e}")
|
|
477
|
+
# Continue without signature
|
|
478
|
+
|
|
479
|
+
# Add the task (with or without signature)
|
|
480
|
+
return add_task(task, db_path=db_path)
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def get_recent_completed_tasks(
|
|
484
|
+
occurrence_id: str = "default", limit: int = 10, db_path: Optional[str] = None
|
|
485
|
+
) -> List[Task]:
|
|
486
|
+
tasks_list = get_all_tasks(occurrence_id, db_path=db_path)
|
|
487
|
+
completed = [t for t in tasks_list if getattr(t, "status", None) == TaskStatus.COMPLETED]
|
|
488
|
+
completed_sorted = sorted(completed, key=lambda t: getattr(t, "updated_at", ""), reverse=True)
|
|
489
|
+
return completed_sorted[:limit]
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
def get_top_tasks(occurrence_id: str = "default", limit: int = 10, db_path: Optional[str] = None) -> List[Task]:
|
|
493
|
+
"""Get top pending tasks for occurrence ordered by priority (highest first) then by creation date."""
|
|
494
|
+
tasks_list = get_all_tasks(occurrence_id, db_path=db_path)
|
|
495
|
+
# Filter to PENDING tasks only - exclude COMPLETED, DEFERRED, FAILED, REJECTED
|
|
496
|
+
pending = [t for t in tasks_list if getattr(t, "status", None) == TaskStatus.PENDING]
|
|
497
|
+
sorted_tasks = sorted(pending, key=lambda t: (-getattr(t, "priority", 0), getattr(t, "created_at", "")))
|
|
498
|
+
return sorted_tasks[:limit]
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
def get_pending_tasks_for_activation(
|
|
502
|
+
occurrence_id: str = "default", limit: int = 10, db_path: Optional[str] = None
|
|
503
|
+
) -> List[Task]:
|
|
504
|
+
"""Get pending tasks for occurrence ordered by priority (highest first) then by creation date, with optional limit."""
|
|
505
|
+
pending_tasks = get_tasks_by_status(TaskStatus.PENDING, occurrence_id, db_path=db_path)
|
|
506
|
+
# Sort by priority (descending) then by created_at (ascending for oldest first)
|
|
507
|
+
sorted_tasks = sorted(pending_tasks, key=lambda t: (-getattr(t, "priority", 0), getattr(t, "created_at", "")))
|
|
508
|
+
return sorted_tasks[:limit]
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def count_tasks(
|
|
512
|
+
status: Optional[TaskStatus] = None, occurrence_id: str = "default", db_path: Optional[str] = None
|
|
513
|
+
) -> int:
|
|
514
|
+
"""
|
|
515
|
+
Count tasks using SQL COUNT(*) for performance.
|
|
516
|
+
|
|
517
|
+
This function uses a SQL COUNT(*) query instead of loading all tasks into memory,
|
|
518
|
+
which prevents event loop blocking when counting large numbers of tasks.
|
|
519
|
+
|
|
520
|
+
Args:
|
|
521
|
+
status: Optional task status to filter by
|
|
522
|
+
occurrence_id: Agent occurrence ID (default: "default")
|
|
523
|
+
db_path: Optional database path
|
|
524
|
+
|
|
525
|
+
Returns:
|
|
526
|
+
Number of tasks matching the criteria
|
|
527
|
+
"""
|
|
528
|
+
try:
|
|
529
|
+
with get_db_connection(db_path) as conn:
|
|
530
|
+
# Get adapter AFTER connection is established to ensure correct dialect
|
|
531
|
+
# (get_db_connection calls init_dialect which sets the global adapter)
|
|
532
|
+
adapter = get_adapter()
|
|
533
|
+
cursor = conn.cursor()
|
|
534
|
+
|
|
535
|
+
if status:
|
|
536
|
+
sql = adapter.translate_placeholders(
|
|
537
|
+
"SELECT COUNT(*) FROM tasks WHERE agent_occurrence_id = ? AND status = ?"
|
|
538
|
+
)
|
|
539
|
+
cursor.execute(sql, (occurrence_id, status.value))
|
|
540
|
+
else:
|
|
541
|
+
sql = adapter.translate_placeholders("SELECT COUNT(*) FROM tasks WHERE agent_occurrence_id = ?")
|
|
542
|
+
cursor.execute(sql, (occurrence_id,))
|
|
543
|
+
|
|
544
|
+
result = cursor.fetchone()
|
|
545
|
+
return adapter.extract_scalar(result) or 0
|
|
546
|
+
except Exception as e:
|
|
547
|
+
logger.exception(f"Failed to count tasks for occurrence {occurrence_id}: {e}")
|
|
548
|
+
return 0
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
def delete_tasks_by_ids(task_ids: List[str], db_path: Optional[str] = None) -> bool:
|
|
552
|
+
"""Deletes tasks and their associated thoughts and feedback_mappings with the given IDs from the database."""
|
|
553
|
+
if not task_ids:
|
|
554
|
+
logger.warning("No task IDs provided for deletion.")
|
|
555
|
+
return False
|
|
556
|
+
|
|
557
|
+
logger.warning(f"DELETE_OPERATION: delete_tasks_by_ids called with {len(task_ids)} tasks: {task_ids}")
|
|
558
|
+
import traceback
|
|
559
|
+
|
|
560
|
+
logger.warning(f"DELETE_OPERATION: Called from: {''.join(traceback.format_stack()[-3:-1])}")
|
|
561
|
+
|
|
562
|
+
placeholders = ",".join("?" for _ in task_ids)
|
|
563
|
+
|
|
564
|
+
sql_get_thought_ids = f"SELECT thought_id FROM thoughts WHERE source_task_id IN ({placeholders})" # nosec B608 - placeholders are '?' strings
|
|
565
|
+
sql_delete_feedback_mappings = "DELETE FROM feedback_mappings WHERE target_thought_id IN ({})"
|
|
566
|
+
sql_delete_thoughts = (
|
|
567
|
+
f"DELETE FROM thoughts WHERE source_task_id IN ({placeholders})" # nosec B608 - placeholders are '?' strings
|
|
568
|
+
)
|
|
569
|
+
sql_delete_tasks = (
|
|
570
|
+
f"DELETE FROM tasks WHERE task_id IN ({placeholders})" # nosec B608 - placeholders are '?' strings
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
deleted_count = 0
|
|
574
|
+
try:
|
|
575
|
+
with get_db_connection(db_path) as conn:
|
|
576
|
+
cursor = conn.cursor()
|
|
577
|
+
|
|
578
|
+
cursor.execute(sql_get_thought_ids, task_ids)
|
|
579
|
+
thought_rows = cursor.fetchall()
|
|
580
|
+
thought_ids_to_delete = [row["thought_id"] for row in thought_rows]
|
|
581
|
+
|
|
582
|
+
if thought_ids_to_delete:
|
|
583
|
+
feedback_placeholders = ",".join("?" for _ in thought_ids_to_delete)
|
|
584
|
+
current_sql_delete_feedback_mappings = sql_delete_feedback_mappings.format(
|
|
585
|
+
feedback_placeholders
|
|
586
|
+
) # nosec B608 - placeholders are '?' strings
|
|
587
|
+
cursor.execute(current_sql_delete_feedback_mappings, thought_ids_to_delete)
|
|
588
|
+
logger.info(
|
|
589
|
+
f"Deleted {cursor.rowcount} associated feedback mappings for thought IDs: {thought_ids_to_delete}."
|
|
590
|
+
)
|
|
591
|
+
else:
|
|
592
|
+
logger.info(f"No associated feedback mappings found for task IDs: {task_ids}.")
|
|
593
|
+
|
|
594
|
+
cursor.execute(sql_delete_thoughts, task_ids)
|
|
595
|
+
thoughts_deleted = cursor.rowcount
|
|
596
|
+
logger.warning(f"DELETE_OPERATION: Deleted {thoughts_deleted} thoughts for tasks: {task_ids}")
|
|
597
|
+
logger.info(f"Deleted {thoughts_deleted} associated thoughts for task IDs: {task_ids}.")
|
|
598
|
+
|
|
599
|
+
cursor.execute(sql_delete_tasks, task_ids)
|
|
600
|
+
deleted_count = cursor.rowcount
|
|
601
|
+
|
|
602
|
+
conn.commit()
|
|
603
|
+
|
|
604
|
+
if deleted_count > 0:
|
|
605
|
+
logger.info(f"Successfully deleted {deleted_count} task(s) with IDs: {task_ids}.")
|
|
606
|
+
return True
|
|
607
|
+
logger.warning(f"No tasks found with IDs: {task_ids} for deletion (or they were already deleted).")
|
|
608
|
+
return False
|
|
609
|
+
except Exception as e:
|
|
610
|
+
logger.exception(f"Failed to delete tasks with IDs {task_ids}: {e}")
|
|
611
|
+
return False
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
def get_tasks_older_than(
|
|
615
|
+
older_than_timestamp: str, occurrence_id: str = "default", db_path: Optional[str] = None
|
|
616
|
+
) -> List[Task]:
|
|
617
|
+
"""Get all tasks for occurrence with created_at older than the given ISO timestamp, returning Task objects."""
|
|
618
|
+
sql = "SELECT * FROM tasks WHERE created_at < ? AND agent_occurrence_id = ?"
|
|
619
|
+
tasks_list: List[Any] = []
|
|
620
|
+
try:
|
|
621
|
+
with get_db_connection(db_path) as conn:
|
|
622
|
+
cursor = conn.cursor()
|
|
623
|
+
cursor.execute(sql, (older_than_timestamp, occurrence_id))
|
|
624
|
+
rows = cursor.fetchall()
|
|
625
|
+
for row in rows:
|
|
626
|
+
tasks_list.append(map_row_to_task(row))
|
|
627
|
+
except Exception as e:
|
|
628
|
+
logger.exception(f"Failed to get tasks older than {older_than_timestamp} for occurrence {occurrence_id}: {e}")
|
|
629
|
+
return tasks_list
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
def get_active_task_for_channel(
|
|
633
|
+
channel_id: str, occurrence_id: str = "default", db_path: Optional[str] = None
|
|
634
|
+
) -> Optional[Task]:
|
|
635
|
+
"""Get the active task for a specific channel and occurrence, if one exists.
|
|
636
|
+
|
|
637
|
+
Args:
|
|
638
|
+
channel_id: The channel to check
|
|
639
|
+
occurrence_id: Runtime occurrence ID (default: "default")
|
|
640
|
+
db_path: Optional database path
|
|
641
|
+
|
|
642
|
+
Returns:
|
|
643
|
+
The active task for the channel in this occurrence, or None if no active task exists
|
|
644
|
+
"""
|
|
645
|
+
sql = """SELECT * FROM tasks
|
|
646
|
+
WHERE channel_id = ? AND status = ? AND agent_occurrence_id = ?
|
|
647
|
+
ORDER BY created_at DESC LIMIT 1"""
|
|
648
|
+
try:
|
|
649
|
+
with get_db_connection(db_path) as conn:
|
|
650
|
+
cursor = conn.cursor()
|
|
651
|
+
cursor.execute(sql, (channel_id, TaskStatus.ACTIVE.value, occurrence_id))
|
|
652
|
+
row = cursor.fetchone()
|
|
653
|
+
if row:
|
|
654
|
+
task = map_row_to_task(row)
|
|
655
|
+
logger.info(
|
|
656
|
+
f"[GET_ACTIVE_TASK] Found active task for channel {channel_id}: task_id={task.task_id}, description={task.description[:100] if task.description else 'N/A'}"
|
|
657
|
+
)
|
|
658
|
+
return task
|
|
659
|
+
else:
|
|
660
|
+
logger.info(f"[GET_ACTIVE_TASK] No active task found for channel {channel_id}")
|
|
661
|
+
return None
|
|
662
|
+
except Exception as e:
|
|
663
|
+
logger.exception(f"Failed to get active task for channel {channel_id} occurrence {occurrence_id}: {e}")
|
|
664
|
+
return None
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
def set_task_updated_info_flag(
|
|
668
|
+
task_id: str,
|
|
669
|
+
updated_content: str,
|
|
670
|
+
occurrence_id: str,
|
|
671
|
+
time_service: TimeServiceProtocol,
|
|
672
|
+
db_path: Optional[str] = None,
|
|
673
|
+
) -> bool:
|
|
674
|
+
"""Set the updated_info_available flag on a task with new observation content.
|
|
675
|
+
|
|
676
|
+
This function checks if the task has already passed conscience checks. If the task
|
|
677
|
+
has passed conscience with any action OTHER than PONDER, it returns False (too late).
|
|
678
|
+
If the task hasn't passed conscience yet, or passed with PONDER, it sets the flag
|
|
679
|
+
and returns True.
|
|
680
|
+
|
|
681
|
+
Args:
|
|
682
|
+
task_id: The task to update
|
|
683
|
+
updated_content: The new observation content
|
|
684
|
+
occurrence_id: Runtime occurrence ID for safety check
|
|
685
|
+
time_service: Time service for timestamps
|
|
686
|
+
db_path: Optional database path
|
|
687
|
+
|
|
688
|
+
Returns:
|
|
689
|
+
True if flag was set successfully, False if task already committed to action or
|
|
690
|
+
doesn't belong to this occurrence
|
|
691
|
+
"""
|
|
692
|
+
# First, verify the task belongs to this occurrence
|
|
693
|
+
task = get_task_by_id(task_id, occurrence_id, db_path)
|
|
694
|
+
if not task or task.agent_occurrence_id != occurrence_id:
|
|
695
|
+
logger.warning(
|
|
696
|
+
f"Task {task_id} does not belong to occurrence {occurrence_id}, cannot set updated_info_available flag"
|
|
697
|
+
)
|
|
698
|
+
return False
|
|
699
|
+
|
|
700
|
+
# Check if task has any completed thoughts with non-PONDER action
|
|
701
|
+
from ciris_engine.logic.persistence.models.thoughts import get_thoughts_by_task_id
|
|
702
|
+
|
|
703
|
+
thoughts = get_thoughts_by_task_id(task_id, occurrence_id, db_path)
|
|
704
|
+
|
|
705
|
+
# Check if any thought is completed with a non-PONDER action
|
|
706
|
+
for thought in thoughts:
|
|
707
|
+
if thought.status == ThoughtStatus.COMPLETED: # Thoughts use ThoughtStatus enum
|
|
708
|
+
# Check if final_action exists and is not PONDER
|
|
709
|
+
if thought.final_action:
|
|
710
|
+
action_type = thought.final_action.action_type
|
|
711
|
+
# If action is anything other than PONDER, it's too late
|
|
712
|
+
if action_type != "PONDER" and action_type != HandlerActionType.PONDER.value:
|
|
713
|
+
logger.info(
|
|
714
|
+
f"Task {task_id} already committed to action {action_type}, "
|
|
715
|
+
f"cannot set updated_info_available flag"
|
|
716
|
+
)
|
|
717
|
+
return False
|
|
718
|
+
|
|
719
|
+
# Safe to update - either no thoughts completed yet, or only PONDER actions
|
|
720
|
+
sql = """
|
|
721
|
+
UPDATE tasks
|
|
722
|
+
SET updated_info_available = 1,
|
|
723
|
+
updated_info_content = ?,
|
|
724
|
+
updated_at = ?
|
|
725
|
+
WHERE task_id = ? AND agent_occurrence_id = ?
|
|
726
|
+
"""
|
|
727
|
+
params = (updated_content, time_service.now_iso(), task_id, occurrence_id)
|
|
728
|
+
try:
|
|
729
|
+
with get_db_connection(db_path) as conn:
|
|
730
|
+
cursor = conn.execute(sql, params)
|
|
731
|
+
conn.commit()
|
|
732
|
+
if cursor.rowcount > 0:
|
|
733
|
+
logger.info(f"Set updated_info_available flag for task {task_id}")
|
|
734
|
+
return True
|
|
735
|
+
logger.warning(f"Task {task_id} not found for update in occurrence {occurrence_id}")
|
|
736
|
+
return False
|
|
737
|
+
except Exception as e:
|
|
738
|
+
logger.exception(f"Failed to set updated_info_available flag for task {task_id}: {e}")
|
|
739
|
+
return False
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
# ==================== Multi-Occurrence Shared Task Functions ====================
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
def try_claim_shared_task(
|
|
746
|
+
task_type: str,
|
|
747
|
+
channel_id: str,
|
|
748
|
+
description: str,
|
|
749
|
+
priority: int,
|
|
750
|
+
time_service: TimeServiceProtocol,
|
|
751
|
+
db_path: Optional[str] = None,
|
|
752
|
+
) -> tuple[Task, bool]:
|
|
753
|
+
"""Atomically create or retrieve a shared agent-level task.
|
|
754
|
+
|
|
755
|
+
Uses deterministic task_id based on date to prevent race conditions when
|
|
756
|
+
multiple occurrences try to create the same shared task simultaneously.
|
|
757
|
+
|
|
758
|
+
The task is created with agent_occurrence_id="__shared__" to make it visible
|
|
759
|
+
to all occurrences of the agent.
|
|
760
|
+
|
|
761
|
+
Args:
|
|
762
|
+
task_type: Type of task (e.g., "wakeup", "shutdown")
|
|
763
|
+
channel_id: Channel where task originated
|
|
764
|
+
description: Task description
|
|
765
|
+
priority: Task priority (0-10)
|
|
766
|
+
time_service: Time service for timestamps
|
|
767
|
+
db_path: Optional database path
|
|
768
|
+
|
|
769
|
+
Returns:
|
|
770
|
+
Tuple of (Task, was_created) where was_created=True if this call created
|
|
771
|
+
the task, False if it already existed.
|
|
772
|
+
|
|
773
|
+
Example:
|
|
774
|
+
>>> task, created = try_claim_shared_task("wakeup", "system", "Identity affirmation", 10, time_service)
|
|
775
|
+
>>> if created:
|
|
776
|
+
... print("This occurrence will process wakeup")
|
|
777
|
+
... else:
|
|
778
|
+
... print("Another occurrence already claimed wakeup")
|
|
779
|
+
"""
|
|
780
|
+
from datetime import datetime, timezone
|
|
781
|
+
|
|
782
|
+
# Create deterministic task ID based on type and date
|
|
783
|
+
date_str = datetime.now(timezone.utc).strftime("%Y%m%d")
|
|
784
|
+
task_id = f"{task_type.upper()}_SHARED_{date_str}"
|
|
785
|
+
|
|
786
|
+
# First, check if task already exists
|
|
787
|
+
existing = get_task_by_id(task_id, "__shared__", db_path)
|
|
788
|
+
if existing:
|
|
789
|
+
# CRITICAL: Only reuse task if it's in a valid reusable state
|
|
790
|
+
# Stale tasks (completed, failed, or very old active tasks) should NOT be reused
|
|
791
|
+
# This prevents infinite loops from reusing tasks with completed seed thoughts
|
|
792
|
+
|
|
793
|
+
from datetime import timedelta
|
|
794
|
+
|
|
795
|
+
# Parse created_at string to datetime for age calculation
|
|
796
|
+
created_at = datetime.fromisoformat(existing.created_at.replace("Z", "+00:00"))
|
|
797
|
+
task_age = time_service.now() - created_at
|
|
798
|
+
is_fresh = task_age < timedelta(minutes=10) # Fresh if created within last 10 minutes
|
|
799
|
+
is_reusable_status = existing.status in [TaskStatus.PENDING, TaskStatus.ACTIVE]
|
|
800
|
+
|
|
801
|
+
if not is_reusable_status:
|
|
802
|
+
logger.warning(
|
|
803
|
+
f"Shared task {task_id} exists but has terminal status {existing.status.value}. "
|
|
804
|
+
"This stale task should have been cleaned up. Creating new task instead."
|
|
805
|
+
)
|
|
806
|
+
# Delete the stale task and create a new one
|
|
807
|
+
delete_tasks_by_ids([task_id], db_path)
|
|
808
|
+
elif not is_fresh:
|
|
809
|
+
logger.warning(
|
|
810
|
+
f"Shared task {task_id} exists but is stale (age: {task_age}). "
|
|
811
|
+
"This old active task should have been cleaned up. Creating new task instead."
|
|
812
|
+
)
|
|
813
|
+
# Delete the stale task and create a new one
|
|
814
|
+
delete_tasks_by_ids([task_id], db_path)
|
|
815
|
+
else:
|
|
816
|
+
# Task is fresh and in valid state - safe to reuse
|
|
817
|
+
logger.info(
|
|
818
|
+
f"Shared task {task_id} already exists (status={existing.status.value}, age={task_age}), "
|
|
819
|
+
"returning existing task"
|
|
820
|
+
)
|
|
821
|
+
return (existing, False)
|
|
822
|
+
|
|
823
|
+
# Try to create the task with INSERT OR IGNORE for race safety
|
|
824
|
+
# Use dialect adapter for database compatibility
|
|
825
|
+
from ciris_engine.logic.persistence.db.dialect import get_adapter
|
|
826
|
+
|
|
827
|
+
adapter = get_adapter()
|
|
828
|
+
now = time_service.now_iso()
|
|
829
|
+
|
|
830
|
+
columns = [
|
|
831
|
+
"task_id",
|
|
832
|
+
"channel_id",
|
|
833
|
+
"agent_occurrence_id",
|
|
834
|
+
"description",
|
|
835
|
+
"status",
|
|
836
|
+
"priority",
|
|
837
|
+
"created_at",
|
|
838
|
+
"updated_at",
|
|
839
|
+
"parent_task_id",
|
|
840
|
+
"context_json",
|
|
841
|
+
"outcome_json",
|
|
842
|
+
"signed_by",
|
|
843
|
+
"signature",
|
|
844
|
+
"signed_at",
|
|
845
|
+
"updated_info_available",
|
|
846
|
+
"updated_info_content",
|
|
847
|
+
"images_json",
|
|
848
|
+
]
|
|
849
|
+
conflict_columns = ["task_id"] # Primary key constraint (task_id only)
|
|
850
|
+
|
|
851
|
+
sql = adapter.insert_or_ignore("tasks", columns, conflict_columns)
|
|
852
|
+
params = (
|
|
853
|
+
task_id,
|
|
854
|
+
channel_id,
|
|
855
|
+
"__shared__",
|
|
856
|
+
description,
|
|
857
|
+
TaskStatus.PENDING.value,
|
|
858
|
+
priority,
|
|
859
|
+
now,
|
|
860
|
+
now,
|
|
861
|
+
None, # parent_task_id
|
|
862
|
+
None, # context_json
|
|
863
|
+
None, # outcome_json
|
|
864
|
+
None, # signed_by
|
|
865
|
+
None, # signature
|
|
866
|
+
None, # signed_at
|
|
867
|
+
0, # updated_info_available
|
|
868
|
+
None, # updated_info_content
|
|
869
|
+
None, # images_json (shared tasks don't have images)
|
|
870
|
+
)
|
|
871
|
+
|
|
872
|
+
try:
|
|
873
|
+
with get_db_connection(db_path) as conn:
|
|
874
|
+
cursor = conn.execute(sql, params)
|
|
875
|
+
conn.commit()
|
|
876
|
+
|
|
877
|
+
if cursor.rowcount > 0:
|
|
878
|
+
# We successfully created the task
|
|
879
|
+
logger.info(f"Successfully claimed shared task {task_id}")
|
|
880
|
+
created_task = get_task_by_id(task_id, "__shared__", db_path)
|
|
881
|
+
if created_task:
|
|
882
|
+
return (created_task, True)
|
|
883
|
+
else:
|
|
884
|
+
# This shouldn't happen, but handle gracefully
|
|
885
|
+
logger.error(f"Created shared task {task_id} but couldn't retrieve it")
|
|
886
|
+
raise RuntimeError(f"Failed to retrieve newly created shared task {task_id}")
|
|
887
|
+
else:
|
|
888
|
+
# INSERT OR IGNORE returned 0 rows - another occurrence created it between our check and insert
|
|
889
|
+
logger.info(f"Another occurrence claimed shared task {task_id} during race")
|
|
890
|
+
existing = get_task_by_id(task_id, "__shared__", db_path)
|
|
891
|
+
if existing:
|
|
892
|
+
return (existing, False)
|
|
893
|
+
else:
|
|
894
|
+
# This shouldn't happen, but handle gracefully
|
|
895
|
+
logger.error(f"INSERT OR IGNORE for {task_id} returned 0 rows but task doesn't exist")
|
|
896
|
+
raise RuntimeError(f"Shared task {task_id} creation race condition failed")
|
|
897
|
+
|
|
898
|
+
except Exception as e:
|
|
899
|
+
logger.exception(f"Failed to claim shared task {task_id}: {e}")
|
|
900
|
+
raise
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
def get_shared_task_status(
|
|
904
|
+
task_type: str, within_hours: int = 24, db_path: Optional[str] = None
|
|
905
|
+
) -> Optional[TaskStatus]:
|
|
906
|
+
"""Get the status of the most recent shared task of a given type.
|
|
907
|
+
|
|
908
|
+
Args:
|
|
909
|
+
task_type: Type of task (e.g., "wakeup", "shutdown")
|
|
910
|
+
within_hours: Only consider tasks created within this many hours (default: 24)
|
|
911
|
+
db_path: Optional database path
|
|
912
|
+
|
|
913
|
+
Returns:
|
|
914
|
+
TaskStatus enum if task found, None if no recent task exists
|
|
915
|
+
"""
|
|
916
|
+
from datetime import datetime, timedelta, timezone
|
|
917
|
+
|
|
918
|
+
cutoff_time = datetime.now(timezone.utc) - timedelta(hours=within_hours)
|
|
919
|
+
cutoff_iso = cutoff_time.isoformat()
|
|
920
|
+
|
|
921
|
+
sql = """
|
|
922
|
+
SELECT status FROM tasks
|
|
923
|
+
WHERE agent_occurrence_id = '__shared__'
|
|
924
|
+
AND task_id LIKE ?
|
|
925
|
+
AND created_at > ?
|
|
926
|
+
ORDER BY created_at DESC
|
|
927
|
+
LIMIT 1
|
|
928
|
+
"""
|
|
929
|
+
pattern = f"{task_type.upper()}_SHARED_%"
|
|
930
|
+
|
|
931
|
+
try:
|
|
932
|
+
with get_db_connection(db_path) as conn:
|
|
933
|
+
cursor = conn.cursor()
|
|
934
|
+
# Note: PostgreSQLCursorWrapper automatically translates ? to %s
|
|
935
|
+
cursor.execute(sql, (pattern, cutoff_iso))
|
|
936
|
+
row = cursor.fetchone()
|
|
937
|
+
if row:
|
|
938
|
+
return TaskStatus(row["status"])
|
|
939
|
+
return None
|
|
940
|
+
except Exception as e:
|
|
941
|
+
logger.exception(f"Failed to get shared task status for {task_type}: {e}")
|
|
942
|
+
return None
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
def is_shared_task_completed(task_type: str, within_hours: int = 24, db_path: Optional[str] = None) -> bool:
|
|
946
|
+
"""Check if a shared task of the given type has been completed recently.
|
|
947
|
+
|
|
948
|
+
Args:
|
|
949
|
+
task_type: Type of task (e.g., "wakeup", "shutdown")
|
|
950
|
+
within_hours: Only consider tasks created within this many hours (default: 24)
|
|
951
|
+
db_path: Optional database path
|
|
952
|
+
|
|
953
|
+
Returns:
|
|
954
|
+
True if a completed task exists, False otherwise
|
|
955
|
+
"""
|
|
956
|
+
status = get_shared_task_status(task_type, within_hours, db_path)
|
|
957
|
+
return status == TaskStatus.COMPLETED if status else False
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
def get_latest_shared_task(task_type: str, within_hours: int = 24, db_path: Optional[str] = None) -> Optional[Task]:
|
|
961
|
+
"""Get the most recent shared task of a given type.
|
|
962
|
+
|
|
963
|
+
Args:
|
|
964
|
+
task_type: Type of task (e.g., "wakeup", "shutdown")
|
|
965
|
+
within_hours: Only consider tasks created within this many hours (default: 24)
|
|
966
|
+
db_path: Optional database path
|
|
967
|
+
|
|
968
|
+
Returns:
|
|
969
|
+
Task object if found, None otherwise
|
|
970
|
+
"""
|
|
971
|
+
from datetime import datetime, timedelta, timezone
|
|
972
|
+
|
|
973
|
+
cutoff_time = datetime.now(timezone.utc) - timedelta(hours=within_hours)
|
|
974
|
+
cutoff_iso = cutoff_time.isoformat()
|
|
975
|
+
|
|
976
|
+
sql = """
|
|
977
|
+
SELECT * FROM tasks
|
|
978
|
+
WHERE agent_occurrence_id = '__shared__'
|
|
979
|
+
AND task_id LIKE ?
|
|
980
|
+
AND created_at > ?
|
|
981
|
+
ORDER BY created_at DESC
|
|
982
|
+
LIMIT 1
|
|
983
|
+
"""
|
|
984
|
+
pattern = f"{task_type.upper()}_SHARED_%"
|
|
985
|
+
|
|
986
|
+
try:
|
|
987
|
+
with get_db_connection(db_path) as conn:
|
|
988
|
+
cursor = conn.cursor()
|
|
989
|
+
# Note: PostgreSQLCursorWrapper automatically translates ? to %s
|
|
990
|
+
cursor.execute(sql, (pattern, cutoff_iso))
|
|
991
|
+
row = cursor.fetchone()
|
|
992
|
+
if row:
|
|
993
|
+
return map_row_to_task(row)
|
|
994
|
+
return None
|
|
995
|
+
except Exception as e:
|
|
996
|
+
logger.exception(f"Failed to get latest shared task for {task_type}: {e}")
|
|
997
|
+
return None
|
|
998
|
+
|
|
999
|
+
|
|
1000
|
+
def get_task_by_correlation_id(
|
|
1001
|
+
correlation_id: str, occurrence_id: str = "default", db_path: Optional[str] = None
|
|
1002
|
+
) -> Optional[Task]:
|
|
1003
|
+
"""
|
|
1004
|
+
Query for a task by correlation_id (e.g., Reddit post/comment ID).
|
|
1005
|
+
|
|
1006
|
+
Args:
|
|
1007
|
+
correlation_id: The correlation ID to search for (stored in context_json)
|
|
1008
|
+
occurrence_id: Agent occurrence ID (default: "default")
|
|
1009
|
+
db_path: Optional database path
|
|
1010
|
+
|
|
1011
|
+
Returns:
|
|
1012
|
+
Task if found, None otherwise
|
|
1013
|
+
"""
|
|
1014
|
+
from ciris_engine.logic.config.db_paths import get_sqlite_db_full_path
|
|
1015
|
+
from ciris_engine.logic.persistence.db.dialect import get_adapter, init_dialect
|
|
1016
|
+
|
|
1017
|
+
# Initialize dialect based on db_path BEFORE building SQL
|
|
1018
|
+
# This ensures the correct dialect (SQLite or PostgreSQL) is used
|
|
1019
|
+
init_dialect(db_path if db_path else get_sqlite_db_full_path())
|
|
1020
|
+
|
|
1021
|
+
# Use dialect adapter for JSON extraction (SQLite vs PostgreSQL)
|
|
1022
|
+
adapter = get_adapter()
|
|
1023
|
+
json_expr = adapter.json_extract("context_json", "$.correlation_id")
|
|
1024
|
+
|
|
1025
|
+
sql = f"""
|
|
1026
|
+
SELECT * FROM tasks
|
|
1027
|
+
WHERE agent_occurrence_id = {adapter.placeholder()}
|
|
1028
|
+
AND {json_expr} = {adapter.placeholder()}
|
|
1029
|
+
ORDER BY created_at DESC
|
|
1030
|
+
LIMIT 1
|
|
1031
|
+
"""
|
|
1032
|
+
|
|
1033
|
+
try:
|
|
1034
|
+
with get_db_connection(db_path) as conn:
|
|
1035
|
+
cursor = conn.cursor()
|
|
1036
|
+
cursor.execute(sql, (occurrence_id, correlation_id))
|
|
1037
|
+
row = cursor.fetchone()
|
|
1038
|
+
if row:
|
|
1039
|
+
return map_row_to_task(row)
|
|
1040
|
+
return None
|
|
1041
|
+
except Exception as e:
|
|
1042
|
+
logger.exception(f"Failed to get task by correlation_id {correlation_id}: {e}")
|
|
1043
|
+
return None
|