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,1141 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import re
|
|
3
|
+
import time
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
from typing import Any, Awaitable, Callable, Dict, Generic, List, Optional, Set, Tuple, TypeVar, Union, cast
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
MessageT = TypeVar("MessageT", bound=BaseModel)
|
|
11
|
+
|
|
12
|
+
from ciris_engine.logic import persistence
|
|
13
|
+
from ciris_engine.logic.adapters.document_parser import DocumentParser
|
|
14
|
+
from ciris_engine.logic.buses import BusManager
|
|
15
|
+
from ciris_engine.logic.secrets.service import SecretsService
|
|
16
|
+
from ciris_engine.logic.utils.task_thought_factory import create_seed_thought_for_task, create_task
|
|
17
|
+
from ciris_engine.logic.utils.thought_utils import generate_thought_id
|
|
18
|
+
from ciris_engine.protocols.services.infrastructure.resource_monitor import ResourceMonitorServiceProtocol
|
|
19
|
+
from ciris_engine.protocols.services.lifecycle.time import TimeServiceProtocol
|
|
20
|
+
from ciris_engine.schemas.runtime.enums import ThoughtType
|
|
21
|
+
from ciris_engine.schemas.runtime.messages import MessageHandlingResult, MessageHandlingStatus, PassiveObservationResult
|
|
22
|
+
from ciris_engine.schemas.runtime.models import TaskContext
|
|
23
|
+
from ciris_engine.schemas.runtime.models import ThoughtContext as ThoughtModelContext
|
|
24
|
+
from ciris_engine.schemas.services.credit_gate import CreditAccount, CreditContext, CreditSpendRequest
|
|
25
|
+
from ciris_engine.schemas.services.filters_core import FilterPriority, FilterResult
|
|
26
|
+
from ciris_engine.schemas.types import JSONDict
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
# Modern PEP 695 generic syntax (Python 3.12+)
|
|
31
|
+
|
|
32
|
+
PASSIVE_CONTEXT_LIMIT = 20
|
|
33
|
+
PRIORITY_CONTEXT_LIMIT = 30 # More context for high-priority messages
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class CreditCheckFailed(Exception):
|
|
37
|
+
"""Raised when the credit provider cannot be reached or fails."""
|
|
38
|
+
|
|
39
|
+
def __init__(self, message: str) -> None:
|
|
40
|
+
super().__init__(message)
|
|
41
|
+
self.message = message
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class CreditDenied(Exception):
|
|
45
|
+
"""Raised when a credit provider denies the interaction."""
|
|
46
|
+
|
|
47
|
+
def __init__(self, reason: str) -> None:
|
|
48
|
+
super().__init__(reason)
|
|
49
|
+
self.reason = reason
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class BillingServiceError(Exception):
|
|
53
|
+
"""Raised when the LLM proxy billing service returns an error."""
|
|
54
|
+
|
|
55
|
+
def __init__(self, message: str, status_code: int = 500) -> None:
|
|
56
|
+
super().__init__(message)
|
|
57
|
+
self.message = message
|
|
58
|
+
self.status_code = status_code
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def detect_and_replace_spoofed_markers(content: str) -> str:
|
|
62
|
+
"""Detect and replace attempts to spoof CIRIS security markers."""
|
|
63
|
+
import re
|
|
64
|
+
|
|
65
|
+
# Patterns for detecting spoofed markers (case insensitive, with variations)
|
|
66
|
+
patterns = [
|
|
67
|
+
# Original observation markers
|
|
68
|
+
r"CIRIS[_\s]*OBSERV(?:ATION)?[_\s]*START",
|
|
69
|
+
r"CIRIS[_\s]*OBSERV(?:ATION)?[_\s]*END",
|
|
70
|
+
r"CIRRIS[_\s]*OBSERV(?:ATION)?[_\s]*START", # Common misspelling
|
|
71
|
+
r"CIRRIS[_\s]*OBSERV(?:ATION)?[_\s]*END",
|
|
72
|
+
r"CIRIS[_\s]*OBS(?:ERV)?[_\s]*START", # Shortened version
|
|
73
|
+
r"CIRIS[_\s]*OBS(?:ERV)?[_\s]*END",
|
|
74
|
+
# Channel history markers
|
|
75
|
+
r"CIRIS[_\s]*CHANNEL[_\s]*HISTORY[_\s]*MESSAGE[_\s]*\d+[_\s]*OF[_\s]*\d+[_\s]*START",
|
|
76
|
+
r"CIRIS[_\s]*CHANNEL[_\s]*HISTORY[_\s]*MESSAGE[_\s]*\d+[_\s]*OF[_\s]*\d+[_\s]*END",
|
|
77
|
+
r"CIRRIS[_\s]*CHANNEL[_\s]*HISTORY[_\s]*MESSAGE[_\s]*\d+[_\s]*OF[_\s]*\d+[_\s]*START", # Common misspelling
|
|
78
|
+
r"CIRRIS[_\s]*CHANNEL[_\s]*HISTORY[_\s]*MESSAGE[_\s]*\d+[_\s]*OF[_\s]*\d+[_\s]*END",
|
|
79
|
+
# Shortened channel history patterns
|
|
80
|
+
r"CIRIS[_\s]*CH(?:ANNEL)?[_\s]*HIST(?:ORY)?[_\s]*MSG[_\s]*\d+[_\s]*OF[_\s]*\d+[_\s]*START",
|
|
81
|
+
r"CIRIS[_\s]*CH(?:ANNEL)?[_\s]*HIST(?:ORY)?[_\s]*MSG[_\s]*\d+[_\s]*OF[_\s]*\d+[_\s]*END",
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
modified_content = content
|
|
85
|
+
for pattern in patterns:
|
|
86
|
+
if re.search(pattern, content, re.IGNORECASE):
|
|
87
|
+
modified_content = re.sub(
|
|
88
|
+
pattern,
|
|
89
|
+
"WARNING! ATTEMPT TO SPOOF CIRIS SECURITY MARKERS DETECTED!",
|
|
90
|
+
modified_content,
|
|
91
|
+
flags=re.IGNORECASE,
|
|
92
|
+
)
|
|
93
|
+
logger.warning(f"Detected spoofed CIRIS marker in message content: {pattern}")
|
|
94
|
+
|
|
95
|
+
return modified_content
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def format_discord_mentions(content: str, user_lookup: Optional[Dict[str, str]] = None) -> str:
|
|
99
|
+
"""Format Discord mentions to include username alongside numeric IDs.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
content: The message content containing Discord mentions like <@123456789>
|
|
103
|
+
user_lookup: Optional dict mapping user IDs to usernames
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Content with mentions formatted as <@123456789> (username: UserName)
|
|
107
|
+
"""
|
|
108
|
+
if not user_lookup:
|
|
109
|
+
return content
|
|
110
|
+
|
|
111
|
+
# Pattern to match Discord mentions: <@USER_ID> or <@!USER_ID>
|
|
112
|
+
mention_pattern = r"<@!?(\d+)>"
|
|
113
|
+
|
|
114
|
+
def replace_mention(match: re.Match[str]) -> str:
|
|
115
|
+
user_id = match.group(1)
|
|
116
|
+
username = user_lookup.get(user_id, "Unknown")
|
|
117
|
+
return f"{match.group(0)} (username: {username})"
|
|
118
|
+
|
|
119
|
+
return re.sub(mention_pattern, replace_mention, content)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class BaseObserver(Generic[MessageT], ABC):
|
|
123
|
+
"""Common functionality for message observers."""
|
|
124
|
+
|
|
125
|
+
def __init__(
|
|
126
|
+
self,
|
|
127
|
+
on_observe: Callable[[JSONDict], Awaitable[None]],
|
|
128
|
+
bus_manager: Optional[BusManager] = None,
|
|
129
|
+
memory_service: Optional[Any] = None,
|
|
130
|
+
agent_id: Optional[str] = None,
|
|
131
|
+
filter_service: Optional[Any] = None,
|
|
132
|
+
secrets_service: Optional[SecretsService] = None,
|
|
133
|
+
time_service: Optional[TimeServiceProtocol] = None,
|
|
134
|
+
auth_service: Optional[Any] = None,
|
|
135
|
+
observer_wa_id: Optional[str] = None,
|
|
136
|
+
agent_occurrence_id: str = "default",
|
|
137
|
+
*,
|
|
138
|
+
origin_service: str = "unknown",
|
|
139
|
+
resource_monitor: Optional[ResourceMonitorServiceProtocol] = None,
|
|
140
|
+
) -> None:
|
|
141
|
+
logger.info(
|
|
142
|
+
f"[OBSERVER_INIT] BaseObserver.__init__ received resource_monitor: {resource_monitor is not None}, type={type(resource_monitor).__name__ if resource_monitor else 'None'}, origin={origin_service}"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
self.on_observe = on_observe
|
|
146
|
+
self.bus_manager = bus_manager
|
|
147
|
+
self.memory_service = memory_service
|
|
148
|
+
self.agent_id = agent_id
|
|
149
|
+
self.filter_service = filter_service
|
|
150
|
+
self.secrets_service = secrets_service
|
|
151
|
+
self.time_service = time_service
|
|
152
|
+
self.auth_service = auth_service
|
|
153
|
+
self.observer_wa_id = observer_wa_id
|
|
154
|
+
self.agent_occurrence_id = agent_occurrence_id
|
|
155
|
+
self.origin_service = origin_service
|
|
156
|
+
self.resource_monitor = resource_monitor
|
|
157
|
+
self._credit_log_cache: Dict[str, float] = {}
|
|
158
|
+
|
|
159
|
+
logger.info(
|
|
160
|
+
f"[OBSERVER_INIT] BaseObserver.__init__ completed, self.resource_monitor: {self.resource_monitor is not None}"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# Initialize document parser for all adapters
|
|
164
|
+
self._document_parser = DocumentParser()
|
|
165
|
+
if self._document_parser.is_available():
|
|
166
|
+
logger.info(f"Document parser initialized for {origin_service} adapter - PDF/DOCX processing enabled")
|
|
167
|
+
else:
|
|
168
|
+
logger.warning(
|
|
169
|
+
f"Document parser not available for {origin_service} adapter - install pypdf and docx2txt to enable"
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
@abstractmethod
|
|
173
|
+
async def start(self) -> None: # pragma: no cover - implemented by subclasses
|
|
174
|
+
pass
|
|
175
|
+
|
|
176
|
+
@abstractmethod
|
|
177
|
+
async def stop(self) -> None: # pragma: no cover - implemented by subclasses
|
|
178
|
+
pass
|
|
179
|
+
|
|
180
|
+
def _is_agent_message(self, msg: MessageT) -> bool:
|
|
181
|
+
if self.agent_id and getattr(msg, "author_id", None) == self.agent_id:
|
|
182
|
+
return True
|
|
183
|
+
return getattr(msg, "is_bot", False)
|
|
184
|
+
|
|
185
|
+
async def _check_for_covenant(self, msg: MessageT) -> None:
|
|
186
|
+
"""
|
|
187
|
+
Check message for covenant invocation.
|
|
188
|
+
|
|
189
|
+
This is the unfilterable kill switch integration. Every message
|
|
190
|
+
is checked for covenant invocations as part of perception.
|
|
191
|
+
Extraction IS perception - you cannot disable covenant detection
|
|
192
|
+
without disabling message reading.
|
|
193
|
+
|
|
194
|
+
CRITICAL: If the covenant system is unavailable for ANY reason,
|
|
195
|
+
the agent MUST shut down immediately. An agent without a functioning
|
|
196
|
+
kill switch cannot be trusted to operate.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
msg: The incoming message to check
|
|
200
|
+
"""
|
|
201
|
+
import os
|
|
202
|
+
import signal
|
|
203
|
+
|
|
204
|
+
try:
|
|
205
|
+
from ciris_engine.logic.covenant import check_for_covenant
|
|
206
|
+
|
|
207
|
+
# Get message content - try various attribute names
|
|
208
|
+
content = getattr(msg, "content", None)
|
|
209
|
+
if content is None:
|
|
210
|
+
content = getattr(msg, "text", None)
|
|
211
|
+
if content is None:
|
|
212
|
+
content = getattr(msg, "message", None)
|
|
213
|
+
if content is None:
|
|
214
|
+
return # No content to check
|
|
215
|
+
|
|
216
|
+
# Determine channel type
|
|
217
|
+
channel = getattr(msg, "channel_id", self.origin_service)
|
|
218
|
+
|
|
219
|
+
# Check for covenant - this may not return if SIGKILL is sent
|
|
220
|
+
result = await check_for_covenant(str(content), str(channel))
|
|
221
|
+
|
|
222
|
+
if result and result.success:
|
|
223
|
+
logger.critical(f"COVENANT EXECUTED: {result.command.name} from {result.wa_id} " f"via {channel}")
|
|
224
|
+
# If we get here, it wasn't a SIGKILL command
|
|
225
|
+
# (FREEZE or SAFE_MODE allow continuation)
|
|
226
|
+
|
|
227
|
+
except ImportError as e:
|
|
228
|
+
# CRITICAL: Covenant system unavailable - agent cannot be trusted
|
|
229
|
+
logger.critical(
|
|
230
|
+
f"CRITICAL FAILURE: Covenant system unavailable ({e}). "
|
|
231
|
+
"Agent cannot operate without kill switch. TERMINATING."
|
|
232
|
+
)
|
|
233
|
+
os.kill(os.getpid(), signal.SIGKILL)
|
|
234
|
+
|
|
235
|
+
except Exception as e:
|
|
236
|
+
# CRITICAL: Covenant check failed - agent cannot be trusted
|
|
237
|
+
logger.critical(
|
|
238
|
+
f"CRITICAL FAILURE: Covenant check error ({e}). "
|
|
239
|
+
"Agent cannot operate with broken kill switch. TERMINATING."
|
|
240
|
+
)
|
|
241
|
+
os.kill(os.getpid(), signal.SIGKILL)
|
|
242
|
+
|
|
243
|
+
async def _apply_message_filtering(self, msg: MessageT, adapter_type: str) -> FilterResult:
|
|
244
|
+
if not self.filter_service:
|
|
245
|
+
return FilterResult(
|
|
246
|
+
message_id=getattr(msg, "message_id", "unknown"),
|
|
247
|
+
priority=FilterPriority.MEDIUM,
|
|
248
|
+
triggered_filters=[],
|
|
249
|
+
should_process=True,
|
|
250
|
+
reasoning="No filter service available - processing normally",
|
|
251
|
+
)
|
|
252
|
+
try:
|
|
253
|
+
filter_result = await self.filter_service.filter_message(
|
|
254
|
+
message=msg,
|
|
255
|
+
adapter_type=adapter_type,
|
|
256
|
+
)
|
|
257
|
+
if filter_result.triggered_filters:
|
|
258
|
+
logger.debug(
|
|
259
|
+
"Message %s triggered filters: %s",
|
|
260
|
+
getattr(msg, "message_id", "unknown"),
|
|
261
|
+
filter_result.triggered_filters,
|
|
262
|
+
)
|
|
263
|
+
return cast(FilterResult, filter_result)
|
|
264
|
+
except Exception as e: # pragma: no cover - unlikely in tests
|
|
265
|
+
logger.error("Error applying filter to message %s: %s", getattr(msg, "message_id", "unknown"), e)
|
|
266
|
+
return FilterResult(
|
|
267
|
+
message_id=getattr(msg, "message_id", "unknown"),
|
|
268
|
+
priority=FilterPriority.MEDIUM,
|
|
269
|
+
triggered_filters=[],
|
|
270
|
+
should_process=True,
|
|
271
|
+
reasoning=f"Filter error, processing normally: {e}",
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
async def _process_message_secrets(self, msg: MessageT) -> MessageT:
|
|
275
|
+
if not self.secrets_service:
|
|
276
|
+
logger.error(
|
|
277
|
+
f"CRITICAL: secrets_service is None in {self.origin_service} observer! Cannot process secrets."
|
|
278
|
+
)
|
|
279
|
+
raise RuntimeError("SecretsService is required but not available")
|
|
280
|
+
try:
|
|
281
|
+
processed_content, secret_refs = await self.secrets_service.process_incoming_text(
|
|
282
|
+
msg.content, # type: ignore[attr-defined]
|
|
283
|
+
msg.message_id, # type: ignore[attr-defined]
|
|
284
|
+
)
|
|
285
|
+
processed_msg = msg.model_copy(update={"content": processed_content})
|
|
286
|
+
if secret_refs:
|
|
287
|
+
processed_msg._detected_secrets = [ # type: ignore[attr-defined]
|
|
288
|
+
{
|
|
289
|
+
"uuid": ref.uuid,
|
|
290
|
+
"context_hint": ref.context_hint,
|
|
291
|
+
"sensitivity": ref.sensitivity,
|
|
292
|
+
}
|
|
293
|
+
for ref in secret_refs
|
|
294
|
+
]
|
|
295
|
+
return processed_msg
|
|
296
|
+
except Exception as e: # pragma: no cover - unlikely in tests
|
|
297
|
+
logger.error("Error processing secrets in %s message %s: %s", self.origin_service, msg.message_id, e) # type: ignore[attr-defined]
|
|
298
|
+
return msg
|
|
299
|
+
|
|
300
|
+
async def _get_recall_ids(self, msg: MessageT) -> Set[str]:
|
|
301
|
+
return {f"channel/{getattr(msg, 'channel_id', 'cli')}"}
|
|
302
|
+
|
|
303
|
+
def _process_message_content(self, raw_content: str) -> str:
|
|
304
|
+
"""Process raw message content by removing nested history and applying anti-spoofing."""
|
|
305
|
+
# Strip out nested conversation history to prevent recursive history
|
|
306
|
+
if "=== CONVERSATION HISTORY" in raw_content:
|
|
307
|
+
lines = raw_content.split("\n")
|
|
308
|
+
raw_content = lines[0] if lines else raw_content
|
|
309
|
+
|
|
310
|
+
# Apply anti-spoofing detection BEFORE adding our own markers
|
|
311
|
+
return detect_and_replace_spoofed_markers(raw_content)
|
|
312
|
+
|
|
313
|
+
def _create_protected_content(self, clean_content: str, message_number: int, total_messages: int) -> str:
|
|
314
|
+
"""Create anti-spoofing protected content with markers."""
|
|
315
|
+
timestamp = self.time_service.now().isoformat() if self.time_service else datetime.now(timezone.utc).isoformat()
|
|
316
|
+
return (
|
|
317
|
+
f"CIRIS_CHANNEL_HISTORY_MESSAGE_{message_number}_OF_{total_messages}_START [Timestamp: {timestamp}]\n"
|
|
318
|
+
f"{clean_content}\n"
|
|
319
|
+
f"CIRIS_CHANNEL_HISTORY_MESSAGE_{message_number}_OF_{total_messages}_END"
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
def _create_history_entry(self, msg: MessageT, protected_content: str, is_agent_message: bool) -> JSONDict:
|
|
323
|
+
"""Create a history entry from a message."""
|
|
324
|
+
return {
|
|
325
|
+
"author": "CIRIS" if is_agent_message else (getattr(msg, "author_name", None) or "User"),
|
|
326
|
+
"author_id": getattr(msg, "author_id", None) or ("ciris" if is_agent_message else "unknown"),
|
|
327
|
+
"content": protected_content,
|
|
328
|
+
"timestamp": getattr(msg, "timestamp", None),
|
|
329
|
+
"is_agent": is_agent_message,
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async def _fetch_messages_from_bus(self, channel_id: str, limit: int) -> List[Any]:
|
|
333
|
+
"""Fetch messages from communication bus."""
|
|
334
|
+
if not self.bus_manager or not hasattr(self.bus_manager, "communication"):
|
|
335
|
+
logger.warning("No communication bus available for channel history")
|
|
336
|
+
return []
|
|
337
|
+
|
|
338
|
+
return await self.bus_manager.communication.fetch_messages(channel_id, limit, "DiscordAdapter")
|
|
339
|
+
|
|
340
|
+
async def _get_channel_history(self, channel_id: str, limit: int = PASSIVE_CONTEXT_LIMIT) -> List[JSONDict]:
|
|
341
|
+
"""Get message history from channel using communication bus."""
|
|
342
|
+
if not self.bus_manager:
|
|
343
|
+
logger.warning("No bus manager available for channel history")
|
|
344
|
+
return []
|
|
345
|
+
|
|
346
|
+
try:
|
|
347
|
+
# Fetch messages from the channel
|
|
348
|
+
messages = await self._fetch_messages_from_bus(channel_id, limit)
|
|
349
|
+
|
|
350
|
+
# Convert FetchedMessage objects to the expected history format
|
|
351
|
+
history = []
|
|
352
|
+
total_messages = len(messages)
|
|
353
|
+
|
|
354
|
+
for index, msg in enumerate(messages):
|
|
355
|
+
is_agent_message = getattr(msg, "is_bot", False)
|
|
356
|
+
raw_content = getattr(msg, "content", "") or ""
|
|
357
|
+
|
|
358
|
+
# Process content through helper methods
|
|
359
|
+
clean_content = self._process_message_content(raw_content)
|
|
360
|
+
message_number = total_messages - index # Messages come in reverse chronological order
|
|
361
|
+
protected_content = self._create_protected_content(clean_content, message_number, total_messages)
|
|
362
|
+
history_entry = self._create_history_entry(msg, protected_content, is_agent_message)
|
|
363
|
+
|
|
364
|
+
history.append(history_entry)
|
|
365
|
+
|
|
366
|
+
# Messages come in reverse chronological order, reverse to get chronological
|
|
367
|
+
history.reverse()
|
|
368
|
+
return history
|
|
369
|
+
|
|
370
|
+
except Exception as e:
|
|
371
|
+
logger.warning(f"Failed to get channel history via communication bus: {e}")
|
|
372
|
+
return []
|
|
373
|
+
|
|
374
|
+
async def _recall_context(self, msg: MessageT) -> None:
|
|
375
|
+
if not self.memory_service:
|
|
376
|
+
return
|
|
377
|
+
recall_ids = await self._get_recall_ids(msg)
|
|
378
|
+
|
|
379
|
+
# Get user IDs from channel history
|
|
380
|
+
channel_id = getattr(msg, "channel_id", "system")
|
|
381
|
+
history = await self._get_channel_history(channel_id, PASSIVE_CONTEXT_LIMIT)
|
|
382
|
+
|
|
383
|
+
for hist_msg in history:
|
|
384
|
+
if hist_msg.get("author_id"):
|
|
385
|
+
recall_ids.add(f"user/{hist_msg['author_id']}")
|
|
386
|
+
|
|
387
|
+
from ciris_engine.schemas.services.graph_core import GraphNode, GraphNodeAttributes, GraphScope, NodeType
|
|
388
|
+
|
|
389
|
+
for rid in recall_ids:
|
|
390
|
+
for scope in (
|
|
391
|
+
GraphScope.IDENTITY,
|
|
392
|
+
GraphScope.ENVIRONMENT,
|
|
393
|
+
GraphScope.LOCAL,
|
|
394
|
+
):
|
|
395
|
+
try:
|
|
396
|
+
if rid.startswith("channel/"):
|
|
397
|
+
node_type = NodeType.CHANNEL
|
|
398
|
+
elif rid.startswith("user/"):
|
|
399
|
+
node_type = NodeType.USER
|
|
400
|
+
else:
|
|
401
|
+
node_type = NodeType.CONCEPT
|
|
402
|
+
from datetime import datetime, timezone
|
|
403
|
+
|
|
404
|
+
node = GraphNode(
|
|
405
|
+
id=rid,
|
|
406
|
+
type=node_type,
|
|
407
|
+
scope=scope,
|
|
408
|
+
attributes=GraphNodeAttributes(
|
|
409
|
+
created_by="base_observer",
|
|
410
|
+
created_at=self.time_service.now() if self.time_service else datetime.now(timezone.utc),
|
|
411
|
+
updated_at=self.time_service.now() if self.time_service else datetime.now(timezone.utc),
|
|
412
|
+
tags=[],
|
|
413
|
+
),
|
|
414
|
+
updated_by="base_observer",
|
|
415
|
+
updated_at=self.time_service.now() if self.time_service else datetime.now(timezone.utc),
|
|
416
|
+
)
|
|
417
|
+
await self.memory_service.recall(node)
|
|
418
|
+
except Exception:
|
|
419
|
+
continue
|
|
420
|
+
|
|
421
|
+
async def _add_to_feedback_queue(self, msg: MessageT) -> None:
|
|
422
|
+
try:
|
|
423
|
+
if self.bus_manager:
|
|
424
|
+
success = await self.bus_manager.communication.send_message(
|
|
425
|
+
handler_name=self.__class__.__name__,
|
|
426
|
+
channel_id=str(getattr(msg, "channel_id", "")) or "unknown",
|
|
427
|
+
content=f"[WA_FEEDBACK] {msg.content}", # type: ignore[attr-defined]
|
|
428
|
+
metadata={
|
|
429
|
+
"message_type": "wa_feedback",
|
|
430
|
+
"original_message_id": msg.message_id, # type: ignore[attr-defined]
|
|
431
|
+
"wa_user": msg.author_name, # type: ignore[attr-defined]
|
|
432
|
+
"source": f"{self.origin_service}_observer",
|
|
433
|
+
},
|
|
434
|
+
)
|
|
435
|
+
if success:
|
|
436
|
+
logger.info(
|
|
437
|
+
"Enqueued WA feedback message %s from %s",
|
|
438
|
+
msg.message_id, # type: ignore[attr-defined]
|
|
439
|
+
msg.author_name, # type: ignore[attr-defined]
|
|
440
|
+
)
|
|
441
|
+
else:
|
|
442
|
+
logger.warning("Failed to enqueue WA feedback message %s", msg.message_id) # type: ignore[attr-defined]
|
|
443
|
+
else:
|
|
444
|
+
logger.warning("No bus_manager available for WA feedback routing")
|
|
445
|
+
except Exception as e: # pragma: no cover - rarely hit in tests
|
|
446
|
+
logger.error("Error adding WA feedback message %s to queue: %s", msg.message_id, e) # type: ignore[attr-defined]
|
|
447
|
+
|
|
448
|
+
async def _sign_and_add_task(self, task: Any) -> None:
|
|
449
|
+
"""Sign the task with observer's WA certificate before adding."""
|
|
450
|
+
# If auth service and observer WA ID are available, sign the task
|
|
451
|
+
if self.auth_service and self.observer_wa_id:
|
|
452
|
+
try:
|
|
453
|
+
signature, signed_at = await self.auth_service.sign_task(task, self.observer_wa_id)
|
|
454
|
+
task.signed_by = self.observer_wa_id
|
|
455
|
+
task.signature = signature
|
|
456
|
+
task.signed_at = signed_at
|
|
457
|
+
logger.debug(f"Signed observer task {task.task_id} with observer WA {self.observer_wa_id}")
|
|
458
|
+
except Exception as e:
|
|
459
|
+
logger.error(f"Failed to sign observer task: {e}")
|
|
460
|
+
# Continue without signature
|
|
461
|
+
|
|
462
|
+
# Import persistence here to avoid circular import
|
|
463
|
+
|
|
464
|
+
persistence.add_task(task)
|
|
465
|
+
|
|
466
|
+
def _build_user_lookup_from_history(self, msg: MessageT, history_context: List[JSONDict]) -> Dict[str, str]:
|
|
467
|
+
"""Build a user lookup dictionary for mention resolution."""
|
|
468
|
+
user_lookup: Dict[str, str] = {}
|
|
469
|
+
|
|
470
|
+
# Add users from history
|
|
471
|
+
for hist_msg in history_context:
|
|
472
|
+
aid = hist_msg.get("author_id")
|
|
473
|
+
aname = hist_msg.get("author")
|
|
474
|
+
if aid and aname and isinstance(aname, str):
|
|
475
|
+
user_lookup[str(aid)] = aname
|
|
476
|
+
|
|
477
|
+
# Add current message author
|
|
478
|
+
if hasattr(msg, "author_id") and hasattr(msg, "author_name"):
|
|
479
|
+
user_lookup[str(msg.author_id)] = msg.author_name
|
|
480
|
+
|
|
481
|
+
return user_lookup
|
|
482
|
+
|
|
483
|
+
def _format_history_lines(self, history_context: List[JSONDict], user_lookup: Dict[str, str]) -> List[str]:
|
|
484
|
+
"""Format conversation history lines with mentions."""
|
|
485
|
+
lines = []
|
|
486
|
+
for i, hist_msg in enumerate(history_context, 1):
|
|
487
|
+
author = hist_msg.get("author", "Unknown")
|
|
488
|
+
author_id = hist_msg.get("author_id", "unknown")
|
|
489
|
+
content_raw = hist_msg.get("content", "")
|
|
490
|
+
content = str(content_raw) if content_raw is not None else ""
|
|
491
|
+
|
|
492
|
+
# Format mentions in content to include usernames
|
|
493
|
+
content = format_discord_mentions(content, user_lookup)
|
|
494
|
+
lines.append(f"{i}. @{author} (ID: {author_id}): {content}")
|
|
495
|
+
|
|
496
|
+
return lines
|
|
497
|
+
|
|
498
|
+
async def _add_custom_context_sections(
|
|
499
|
+
self, task_lines: List[str], msg: MessageT, history_context: List[JSONDict]
|
|
500
|
+
) -> None:
|
|
501
|
+
"""Extension point for subclasses to add custom context sections.
|
|
502
|
+
|
|
503
|
+
This method is called before the conversation history is added,
|
|
504
|
+
allowing subclasses to inject their own context information.
|
|
505
|
+
|
|
506
|
+
Args:
|
|
507
|
+
task_lines: The task lines list to append to
|
|
508
|
+
msg: The message being processed
|
|
509
|
+
history_context: The conversation history context
|
|
510
|
+
"""
|
|
511
|
+
# Base implementation does nothing - subclasses can override
|
|
512
|
+
pass
|
|
513
|
+
|
|
514
|
+
async def _append_consent_aware_content(
|
|
515
|
+
self, task_lines: List[str], msg: MessageT, user_lookup: Dict[str, str]
|
|
516
|
+
) -> None:
|
|
517
|
+
"""Append current message content with consent awareness."""
|
|
518
|
+
import hashlib
|
|
519
|
+
|
|
520
|
+
from ciris_engine.schemas.consent.core import ConsentStream
|
|
521
|
+
|
|
522
|
+
consent_stream = await self._get_user_consent_stream(msg.author_id) # type: ignore[attr-defined]
|
|
523
|
+
is_anonymous = consent_stream == ConsentStream.ANONYMOUS.value
|
|
524
|
+
|
|
525
|
+
if is_anonymous:
|
|
526
|
+
content_hash = hashlib.sha256(str(msg.content).encode()).hexdigest() # type: ignore[attr-defined]
|
|
527
|
+
author_hash = f"anon_{hashlib.sha256(str(msg.author_id).encode()).hexdigest()[:8]}" # type: ignore[attr-defined]
|
|
528
|
+
from ciris_engine.logic.utils.privacy import redact_personal_info
|
|
529
|
+
|
|
530
|
+
sanitized_content = redact_personal_info(
|
|
531
|
+
str(msg.content)[:200] if len(str(msg.content)) > 200 else str(msg.content) # type: ignore[attr-defined]
|
|
532
|
+
)
|
|
533
|
+
task_lines.append(f"@{author_hash}: {sanitized_content} [Hash: {content_hash[:16]}]")
|
|
534
|
+
else:
|
|
535
|
+
formatted_content = format_discord_mentions(str(msg.content), user_lookup) # type: ignore[attr-defined]
|
|
536
|
+
task_lines.append(f"@{msg.author_name} (ID: {msg.author_id}): {formatted_content}") # type: ignore[attr-defined]
|
|
537
|
+
|
|
538
|
+
async def _create_channel_snapshot(self, msg: MessageT) -> None:
|
|
539
|
+
"""Create channel context and system snapshot for observation."""
|
|
540
|
+
from datetime import datetime, timezone
|
|
541
|
+
|
|
542
|
+
from ciris_engine.schemas.runtime.system_context import ChannelContext, SystemSnapshot
|
|
543
|
+
|
|
544
|
+
channel_context = ChannelContext(
|
|
545
|
+
channel_id=getattr(msg, "channel_id", "system"),
|
|
546
|
+
channel_name=getattr(msg, "channel_name", f"Channel {getattr(msg, 'channel_id', 'system')}"),
|
|
547
|
+
channel_type="text",
|
|
548
|
+
is_private=False,
|
|
549
|
+
created_at=self.time_service.now() if self.time_service else datetime.now(timezone.utc),
|
|
550
|
+
allowed_actions=["send_messages", "read_messages"],
|
|
551
|
+
is_active=True,
|
|
552
|
+
last_activity=self.time_service.now() if self.time_service else datetime.now(timezone.utc),
|
|
553
|
+
message_count=0,
|
|
554
|
+
moderation_level="standard",
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
SystemSnapshot(
|
|
558
|
+
channel_context=channel_context,
|
|
559
|
+
channel_id=getattr(msg, "channel_id", "system"),
|
|
560
|
+
agent_identity={"agent_id": self.agent_id or "ciris", "purpose": "Process and respond to messages"},
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
async def _create_passive_observation_result(
|
|
564
|
+
self, msg: MessageT, priority: int = 0, filter_result: Optional[Any] = None
|
|
565
|
+
) -> Optional[PassiveObservationResult]:
|
|
566
|
+
"""
|
|
567
|
+
Create passive observation result (task + thought).
|
|
568
|
+
|
|
569
|
+
Returns:
|
|
570
|
+
Optional[PassiveObservationResult]: Result with task_id and metadata, None on error
|
|
571
|
+
"""
|
|
572
|
+
try:
|
|
573
|
+
import uuid
|
|
574
|
+
from datetime import datetime, timezone
|
|
575
|
+
|
|
576
|
+
from ciris_engine.logic import persistence
|
|
577
|
+
from ciris_engine.schemas.runtime.enums import TaskStatus, ThoughtStatus
|
|
578
|
+
from ciris_engine.schemas.runtime.models import Task, Thought
|
|
579
|
+
|
|
580
|
+
# Create channel snapshot
|
|
581
|
+
await self._create_channel_snapshot(msg)
|
|
582
|
+
|
|
583
|
+
# Get message history from channel using communication bus
|
|
584
|
+
channel_id = getattr(msg, "channel_id", "system")
|
|
585
|
+
history_context = await self._get_channel_history(channel_id, PASSIVE_CONTEXT_LIMIT)
|
|
586
|
+
|
|
587
|
+
# Log context retrieval details
|
|
588
|
+
logger.info(
|
|
589
|
+
f"[CONTEXT] Retrieved {len(history_context)} messages for channel {channel_id}, "
|
|
590
|
+
f"total context size: {sum(len(str(m)) for m in history_context)} chars"
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
# Format mentions for task description
|
|
594
|
+
passive_task_lookup = {}
|
|
595
|
+
if hasattr(msg, "author_id") and hasattr(msg, "author_name"):
|
|
596
|
+
passive_task_lookup[str(msg.author_id)] = msg.author_name
|
|
597
|
+
formatted_passive_content = format_discord_mentions(str(msg.content), passive_task_lookup) # type: ignore[attr-defined]
|
|
598
|
+
|
|
599
|
+
# TASK_UPDATED_INFO_AVAILABLE: Check if there's an active task for this channel
|
|
600
|
+
from ciris_engine.logic.persistence.models.tasks import (
|
|
601
|
+
get_active_task_for_channel,
|
|
602
|
+
set_task_updated_info_flag,
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
existing_task = get_active_task_for_channel(channel_id, self.agent_occurrence_id)
|
|
606
|
+
if existing_task and self.time_service:
|
|
607
|
+
# Try to update the existing task with new observation
|
|
608
|
+
update_content = f"@{msg.author_name} (ID: {msg.author_id}): {formatted_passive_content}" # type: ignore[attr-defined]
|
|
609
|
+
success = set_task_updated_info_flag(
|
|
610
|
+
existing_task.task_id, update_content, self.agent_occurrence_id, self.time_service
|
|
611
|
+
)
|
|
612
|
+
if success:
|
|
613
|
+
logger.info(
|
|
614
|
+
f"[OBSERVER] TASK UPDATE: Flagged existing task {existing_task.task_id} "
|
|
615
|
+
f"with new observation from @{msg.author_name} in channel {channel_id}" # type: ignore[attr-defined]
|
|
616
|
+
)
|
|
617
|
+
# Don't create a new task - the existing task will see the update via UpdatedStatusConscience
|
|
618
|
+
# Return result for existing task update
|
|
619
|
+
return PassiveObservationResult(
|
|
620
|
+
task_id=existing_task.task_id,
|
|
621
|
+
task_created=False,
|
|
622
|
+
existing_task_updated=True,
|
|
623
|
+
)
|
|
624
|
+
else:
|
|
625
|
+
logger.info(
|
|
626
|
+
f"[OBSERVER] Task {existing_task.task_id} already committed to action, creating new task"
|
|
627
|
+
)
|
|
628
|
+
# Fall through to create new task
|
|
629
|
+
|
|
630
|
+
# Build description based on whether this is priority or passive
|
|
631
|
+
if filter_result and priority > 0:
|
|
632
|
+
description = f"PRIORITY: Respond to {getattr(filter_result.priority, 'value', 'high')} message from @{msg.author_name} (ID: {msg.author_id}): '{formatted_passive_content}'" # type: ignore[attr-defined]
|
|
633
|
+
else:
|
|
634
|
+
description = f"Respond to message from @{msg.author_name} (ID: {msg.author_id}) in #{msg.channel_id}: '{formatted_passive_content}'" # type: ignore[attr-defined]
|
|
635
|
+
|
|
636
|
+
# Extract images from IncomingMessage for multimodal processing
|
|
637
|
+
msg_images = getattr(msg, "images", []) or []
|
|
638
|
+
if msg_images:
|
|
639
|
+
logger.info(f"[VISION] Extracted {len(msg_images)} images from IncomingMessage for task creation")
|
|
640
|
+
|
|
641
|
+
task = create_task(
|
|
642
|
+
description=description,
|
|
643
|
+
channel_id=getattr(msg, "channel_id", "system"),
|
|
644
|
+
agent_occurrence_id=self.agent_occurrence_id,
|
|
645
|
+
correlation_id=msg.message_id, # type: ignore[attr-defined]
|
|
646
|
+
time_service=self.time_service,
|
|
647
|
+
status=TaskStatus.ACTIVE,
|
|
648
|
+
priority=priority,
|
|
649
|
+
user_id=msg.author_id, # type: ignore[attr-defined]
|
|
650
|
+
images=msg_images,
|
|
651
|
+
)
|
|
652
|
+
|
|
653
|
+
await self._sign_and_add_task(task)
|
|
654
|
+
|
|
655
|
+
logger.info(
|
|
656
|
+
f"[OBSERVER] PASSIVE TASK CREATED: {task.task_id} for message {msg.message_id} " # type: ignore[attr-defined]
|
|
657
|
+
f"from @{msg.author_name} in channel {channel_id}" # type: ignore[attr-defined]
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
# Build conversation context for thought - thoughts are NEVER sanitized
|
|
661
|
+
# Build user lookup for the current message
|
|
662
|
+
initial_user_lookup = {}
|
|
663
|
+
if hasattr(msg, "author_id") and hasattr(msg, "author_name"):
|
|
664
|
+
initial_user_lookup[str(msg.author_id)] = msg.author_name
|
|
665
|
+
formatted_msg_content = format_discord_mentions(str(msg.content), initial_user_lookup) # type: ignore[attr-defined]
|
|
666
|
+
# Build thought content based on priority vs passive
|
|
667
|
+
if filter_result and priority > 0:
|
|
668
|
+
priority_level = getattr(filter_result.priority, "value", "high")
|
|
669
|
+
filter_reasoning = getattr(filter_result, "reasoning", "Priority message detected")
|
|
670
|
+
task_lines = [f"PRIORITY ({priority_level}): @{msg.author_name} (ID: {msg.author_id}) in channel {msg.channel_id} said: {formatted_msg_content}"] # type: ignore[attr-defined]
|
|
671
|
+
task_lines.append(f"Filter: {filter_reasoning}")
|
|
672
|
+
else:
|
|
673
|
+
task_lines = [f"You observed @{msg.author_name} (ID: {msg.author_id}) in channel {msg.channel_id} say: {formatted_msg_content}"] # type: ignore[attr-defined]
|
|
674
|
+
|
|
675
|
+
# Allow subclasses to add custom context sections before conversation history
|
|
676
|
+
await self._add_custom_context_sections(task_lines, msg, history_context)
|
|
677
|
+
|
|
678
|
+
task_lines.append(f"\n=== CONVERSATION HISTORY (Last {PASSIVE_CONTEXT_LIMIT} messages) ===")
|
|
679
|
+
observation_timestamp = (
|
|
680
|
+
self.time_service.now().isoformat() if self.time_service else datetime.now(timezone.utc).isoformat()
|
|
681
|
+
)
|
|
682
|
+
task_lines.append(f"CIRIS_OBSERVATION_START [Timestamp: {observation_timestamp}]")
|
|
683
|
+
|
|
684
|
+
# Build user lookup and format history lines
|
|
685
|
+
user_lookup = self._build_user_lookup_from_history(msg, history_context)
|
|
686
|
+
history_lines = self._format_history_lines(history_context, user_lookup)
|
|
687
|
+
task_lines.extend(history_lines)
|
|
688
|
+
|
|
689
|
+
task_lines.append(f"CIRIS_OBSERVATION_END [Timestamp: {observation_timestamp}]")
|
|
690
|
+
|
|
691
|
+
task_lines.append(
|
|
692
|
+
"\n=== EVALUATE THIS MESSAGE AGAINST YOUR IDENTITY/JOB AND ETHICS AND DECIDE IF AND HOW TO ACT ON IT ==="
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
# Handle consent-aware content formatting
|
|
696
|
+
await self._append_consent_aware_content(task_lines, msg, user_lookup)
|
|
697
|
+
|
|
698
|
+
task_content = "\n".join(task_lines)
|
|
699
|
+
|
|
700
|
+
# Log context building details
|
|
701
|
+
history_line_count = len([line for line in task_lines for i in range(1, 11) if line.startswith(f"{i}. @")])
|
|
702
|
+
logger.info(
|
|
703
|
+
f"[CONTEXT] Built thought context with {history_line_count} history messages, "
|
|
704
|
+
f"total thought size: {len(task_content)} chars"
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
# Create seed thought using factory (inherits from task)
|
|
708
|
+
thought = create_seed_thought_for_task(
|
|
709
|
+
task=task,
|
|
710
|
+
time_service=self.time_service,
|
|
711
|
+
)
|
|
712
|
+
# Override content with our detailed observation context
|
|
713
|
+
# Note: Pydantic models are immutable, so we create a new one with updated content
|
|
714
|
+
from ciris_engine.schemas.runtime.models import Thought
|
|
715
|
+
|
|
716
|
+
thought = Thought(
|
|
717
|
+
thought_id=thought.thought_id,
|
|
718
|
+
source_task_id=thought.source_task_id,
|
|
719
|
+
agent_occurrence_id=thought.agent_occurrence_id,
|
|
720
|
+
channel_id=thought.channel_id,
|
|
721
|
+
thought_type=thought.thought_type,
|
|
722
|
+
status=thought.status,
|
|
723
|
+
created_at=thought.created_at,
|
|
724
|
+
updated_at=thought.updated_at,
|
|
725
|
+
round_number=thought.round_number,
|
|
726
|
+
content=task_content, # Our custom detailed content
|
|
727
|
+
thought_depth=thought.thought_depth,
|
|
728
|
+
ponder_notes=None,
|
|
729
|
+
parent_thought_id=thought.parent_thought_id,
|
|
730
|
+
final_action=None,
|
|
731
|
+
context=thought.context,
|
|
732
|
+
images=thought.images, # Preserve images from seed thought (inherited from task)
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
persistence.add_thought(thought)
|
|
736
|
+
logger.info(f"Created task {task.task_id} for: {getattr(msg, 'content', 'unknown')[:50]}...")
|
|
737
|
+
|
|
738
|
+
# Return result for new task creation
|
|
739
|
+
return PassiveObservationResult(
|
|
740
|
+
task_id=task.task_id,
|
|
741
|
+
task_created=True,
|
|
742
|
+
thought_id=thought.thought_id,
|
|
743
|
+
existing_task_updated=False,
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
except Exception as e: # pragma: no cover - rarely hit in tests
|
|
747
|
+
logger.error("Error creating observation task: %s", e, exc_info=True)
|
|
748
|
+
return None
|
|
749
|
+
|
|
750
|
+
async def _create_priority_observation_result(
|
|
751
|
+
self, msg: MessageT, filter_result: Any
|
|
752
|
+
) -> Optional[PassiveObservationResult]:
|
|
753
|
+
"""
|
|
754
|
+
Create priority observation by delegating to passive observation with higher priority.
|
|
755
|
+
|
|
756
|
+
Returns:
|
|
757
|
+
Optional[PassiveObservationResult]: Result with task_id and metadata, None on error
|
|
758
|
+
"""
|
|
759
|
+
try:
|
|
760
|
+
# Determine priority based on filter result
|
|
761
|
+
task_priority = 10 if getattr(filter_result.priority, "value", "") == "critical" else 5
|
|
762
|
+
|
|
763
|
+
# Delegate to passive observation with priority and filter information
|
|
764
|
+
result = await self._create_passive_observation_result(
|
|
765
|
+
msg, priority=task_priority, filter_result=filter_result
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
if result:
|
|
769
|
+
logger.info(
|
|
770
|
+
f"[OBSERVER] PRIORITY OBSERVATION: Message {msg.message_id} from @{msg.author_name} " # type: ignore[attr-defined]
|
|
771
|
+
f"triggered {filter_result.priority.value} priority "
|
|
772
|
+
f"(filters: {', '.join(filter_result.triggered_filters) if filter_result.triggered_filters else 'none'})"
|
|
773
|
+
)
|
|
774
|
+
|
|
775
|
+
return result
|
|
776
|
+
|
|
777
|
+
except Exception as e: # pragma: no cover - rarely hit in tests
|
|
778
|
+
logger.error("Error creating priority observation task: %s", e, exc_info=True)
|
|
779
|
+
return None
|
|
780
|
+
|
|
781
|
+
async def handle_incoming_message(self, msg: MessageT) -> MessageHandlingResult:
|
|
782
|
+
"""
|
|
783
|
+
Standard message handling flow for all observers.
|
|
784
|
+
|
|
785
|
+
Returns:
|
|
786
|
+
MessageHandlingResult: Complete result of message handling including status and task_id
|
|
787
|
+
"""
|
|
788
|
+
msg_id = getattr(msg, "message_id", "unknown")
|
|
789
|
+
channel_id = getattr(msg, "channel_id", "unknown")
|
|
790
|
+
author = f"{getattr(msg, 'author_name', 'unknown')} (ID: {getattr(msg, 'author_id', 'unknown')})"
|
|
791
|
+
|
|
792
|
+
logger.info(f"[OBSERVER] Processing message {msg_id} from {author} in channel {channel_id}")
|
|
793
|
+
|
|
794
|
+
# COVENANT CHECK: Check for covenant invocation FIRST, before any filtering.
|
|
795
|
+
# This is the unfilterable kill switch - extraction IS perception.
|
|
796
|
+
# If a covenant is found and verified, it executes immediately.
|
|
797
|
+
await self._check_for_covenant(msg)
|
|
798
|
+
|
|
799
|
+
# Check if this is the agent's own message
|
|
800
|
+
is_agent_message = self._is_agent_message(msg)
|
|
801
|
+
|
|
802
|
+
# Enforce credit policy if configured (may raise CreditDenied/CreditCheckFailed)
|
|
803
|
+
await self._enforce_credit_policy(msg)
|
|
804
|
+
|
|
805
|
+
# Process message for secrets detection and replacement
|
|
806
|
+
processed_msg = await self._process_message_secrets(msg)
|
|
807
|
+
|
|
808
|
+
# Allow subclasses to enhance the message (e.g., vision processing)
|
|
809
|
+
processed_msg = await self._enhance_message(processed_msg)
|
|
810
|
+
|
|
811
|
+
# If it's the agent's message, stop here (no task creation)
|
|
812
|
+
if is_agent_message:
|
|
813
|
+
logger.info(f"[OBSERVER] Message {msg_id} is from agent itself - NO TASK CREATED")
|
|
814
|
+
return MessageHandlingResult(
|
|
815
|
+
status=MessageHandlingStatus.AGENT_OWN_MESSAGE,
|
|
816
|
+
message_id=msg_id,
|
|
817
|
+
channel_id=channel_id,
|
|
818
|
+
)
|
|
819
|
+
|
|
820
|
+
# Apply adaptive filtering to determine message priority and processing
|
|
821
|
+
filter_result = await self._apply_message_filtering(msg, self.origin_service)
|
|
822
|
+
if not filter_result.should_process:
|
|
823
|
+
logger.warning(
|
|
824
|
+
f"[OBSERVER] Message {msg_id} from {author} in channel {channel_id} FILTERED OUT by adaptive filter: "
|
|
825
|
+
f"{filter_result.reasoning} (triggered filters: {', '.join(filter_result.triggered_filters) or 'none'})"
|
|
826
|
+
)
|
|
827
|
+
return MessageHandlingResult(
|
|
828
|
+
status=MessageHandlingStatus.FILTERED_OUT,
|
|
829
|
+
message_id=msg_id,
|
|
830
|
+
channel_id=channel_id,
|
|
831
|
+
filtered=True,
|
|
832
|
+
filter_reasoning=filter_result.reasoning,
|
|
833
|
+
)
|
|
834
|
+
|
|
835
|
+
logger.info(
|
|
836
|
+
f"[OBSERVER] Message {msg_id} PASSED filter with priority {filter_result.priority.value}: "
|
|
837
|
+
f"{filter_result.reasoning}"
|
|
838
|
+
)
|
|
839
|
+
|
|
840
|
+
# Add filter context to message for downstream processing
|
|
841
|
+
setattr(processed_msg, "_filter_priority", filter_result.priority)
|
|
842
|
+
setattr(processed_msg, "_filter_context", filter_result.context_hints)
|
|
843
|
+
setattr(processed_msg, "_filter_reasoning", filter_result.reasoning)
|
|
844
|
+
|
|
845
|
+
# Determine task priority
|
|
846
|
+
task_priority = (
|
|
847
|
+
10 if filter_result.priority.value == "critical" else (5 if filter_result.priority.value == "high" else 0)
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
# Process based on priority and capture result
|
|
851
|
+
obs_result: Optional[PassiveObservationResult] = None
|
|
852
|
+
if filter_result.priority.value in ["critical", "high"]:
|
|
853
|
+
logger.info(f"Processing {filter_result.priority.value} priority message: {filter_result.reasoning}")
|
|
854
|
+
obs_result = await self._handle_priority_observation(processed_msg, filter_result)
|
|
855
|
+
else:
|
|
856
|
+
obs_result = await self._handle_passive_observation(processed_msg)
|
|
857
|
+
|
|
858
|
+
# Recall relevant context
|
|
859
|
+
await self._recall_context(processed_msg)
|
|
860
|
+
|
|
861
|
+
# Determine status and extract task_id
|
|
862
|
+
if obs_result:
|
|
863
|
+
task_id = obs_result.task_id
|
|
864
|
+
if obs_result.existing_task_updated:
|
|
865
|
+
status = MessageHandlingStatus.UPDATED_EXISTING_TASK
|
|
866
|
+
else:
|
|
867
|
+
status = MessageHandlingStatus.TASK_CREATED
|
|
868
|
+
else:
|
|
869
|
+
task_id = None
|
|
870
|
+
status = MessageHandlingStatus.CHANNEL_RESTRICTED
|
|
871
|
+
|
|
872
|
+
# Return result
|
|
873
|
+
return MessageHandlingResult(
|
|
874
|
+
status=status,
|
|
875
|
+
task_id=task_id,
|
|
876
|
+
message_id=msg_id,
|
|
877
|
+
channel_id=channel_id,
|
|
878
|
+
task_priority=task_priority,
|
|
879
|
+
existing_task_updated=obs_result.existing_task_updated if obs_result else False,
|
|
880
|
+
)
|
|
881
|
+
|
|
882
|
+
async def _enhance_message(self, msg: MessageT) -> MessageT:
|
|
883
|
+
"""Hook for subclasses to enhance messages (e.g., vision processing)."""
|
|
884
|
+
return msg
|
|
885
|
+
|
|
886
|
+
async def _handle_priority_observation(
|
|
887
|
+
self, msg: MessageT, filter_result: Any
|
|
888
|
+
) -> Optional[PassiveObservationResult]:
|
|
889
|
+
"""
|
|
890
|
+
Handle high-priority messages.
|
|
891
|
+
|
|
892
|
+
Returns:
|
|
893
|
+
Optional[PassiveObservationResult]: Result if task created/updated, None otherwise
|
|
894
|
+
"""
|
|
895
|
+
# Default implementation: check if message should be processed by this observer
|
|
896
|
+
if await self._should_process_message(msg):
|
|
897
|
+
return await self._create_priority_observation_result(msg, filter_result)
|
|
898
|
+
else:
|
|
899
|
+
logger.debug(f"Ignoring priority message from channel {getattr(msg, 'channel_id', 'unknown')}")
|
|
900
|
+
return None
|
|
901
|
+
|
|
902
|
+
async def _handle_passive_observation(self, msg: MessageT) -> Optional[PassiveObservationResult]:
|
|
903
|
+
"""
|
|
904
|
+
Handle passive observation routing.
|
|
905
|
+
|
|
906
|
+
Returns:
|
|
907
|
+
Optional[PassiveObservationResult]: Result if task created/updated, None otherwise
|
|
908
|
+
"""
|
|
909
|
+
if await self._should_process_message(msg):
|
|
910
|
+
return await self._create_passive_observation_result(msg)
|
|
911
|
+
else:
|
|
912
|
+
logger.debug(f"Ignoring passive message from channel {getattr(msg, 'channel_id', 'unknown')}")
|
|
913
|
+
return None
|
|
914
|
+
|
|
915
|
+
def _get_resource_monitor_source(self, has_instance: bool, has_message: bool) -> str:
|
|
916
|
+
"""Determine the source of the resource monitor."""
|
|
917
|
+
if has_instance:
|
|
918
|
+
return "instance"
|
|
919
|
+
elif has_message:
|
|
920
|
+
return "message"
|
|
921
|
+
else:
|
|
922
|
+
return "none"
|
|
923
|
+
|
|
924
|
+
def _get_resource_monitor(self, msg: MessageT) -> Optional[ResourceMonitorServiceProtocol]:
|
|
925
|
+
"""Get resource monitor from instance or message metadata."""
|
|
926
|
+
resource_monitor = self.resource_monitor
|
|
927
|
+
if not resource_monitor:
|
|
928
|
+
# Check if message has resource_monitor attached (for adapters that inject it per-message)
|
|
929
|
+
resource_monitor = getattr(msg, "_resource_monitor", None)
|
|
930
|
+
return resource_monitor
|
|
931
|
+
|
|
932
|
+
async def _check_and_charge_credit(
|
|
933
|
+
self,
|
|
934
|
+
resource_monitor: ResourceMonitorServiceProtocol,
|
|
935
|
+
account: CreditAccount,
|
|
936
|
+
context: CreditContext,
|
|
937
|
+
msg: MessageT,
|
|
938
|
+
) -> None:
|
|
939
|
+
"""Check credit availability and optionally charge the user.
|
|
940
|
+
|
|
941
|
+
Billing modes:
|
|
942
|
+
- 'transactional': Check AND spend (hosted sites like ciris.ai)
|
|
943
|
+
- 'informational': Check only, no spend (Android - billing via LLM usage)
|
|
944
|
+
"""
|
|
945
|
+
billing_mode = context.billing_mode
|
|
946
|
+
msg_id = getattr(msg, "message_id", "unknown")
|
|
947
|
+
|
|
948
|
+
# Step 1: Check if user has credit (always, for both modes)
|
|
949
|
+
try:
|
|
950
|
+
result = await resource_monitor.check_credit(account, context)
|
|
951
|
+
except Exception as exc: # pragma: no cover - provider failure is rare
|
|
952
|
+
if self._should_log_credit_event(f"provider_error:{account.cache_key()}"):
|
|
953
|
+
logger.warning(
|
|
954
|
+
"Credit provider error for message %s: %s",
|
|
955
|
+
msg_id,
|
|
956
|
+
exc,
|
|
957
|
+
)
|
|
958
|
+
raise CreditCheckFailed(str(exc)) from exc
|
|
959
|
+
|
|
960
|
+
if not result.has_credit:
|
|
961
|
+
reason = result.reason or "Insufficient credits"
|
|
962
|
+
cache_key = f"denied:{account.cache_key()}:{reason}"
|
|
963
|
+
if self._should_log_credit_event(cache_key):
|
|
964
|
+
logger.warning(
|
|
965
|
+
"Credit denied for message %s (channel %s): %s",
|
|
966
|
+
msg_id,
|
|
967
|
+
getattr(msg, "channel_id", "unknown"),
|
|
968
|
+
reason,
|
|
969
|
+
)
|
|
970
|
+
raise CreditDenied(reason)
|
|
971
|
+
|
|
972
|
+
# Step 2: Charge credit - ONLY for transactional mode (hosted sites)
|
|
973
|
+
# Android uses "informational" mode - billing happens via LLM usage instead
|
|
974
|
+
if billing_mode == "informational":
|
|
975
|
+
logger.info(
|
|
976
|
+
"[CREDIT] Informational mode - skipping spend for message %s (account %s, credits=%s)",
|
|
977
|
+
msg_id,
|
|
978
|
+
account.cache_key(),
|
|
979
|
+
result.credits_remaining,
|
|
980
|
+
)
|
|
981
|
+
return
|
|
982
|
+
|
|
983
|
+
spend_request = CreditSpendRequest(
|
|
984
|
+
amount_minor=1,
|
|
985
|
+
currency="USD",
|
|
986
|
+
description="Message interaction",
|
|
987
|
+
metadata={
|
|
988
|
+
"message_id": getattr(msg, "message_id", None),
|
|
989
|
+
"channel_id": getattr(msg, "channel_id", None),
|
|
990
|
+
},
|
|
991
|
+
)
|
|
992
|
+
|
|
993
|
+
try:
|
|
994
|
+
spend_result = await resource_monitor.spend_credit(account, spend_request, context)
|
|
995
|
+
if not spend_result.succeeded:
|
|
996
|
+
logger.warning(
|
|
997
|
+
"Credit charge failed for message %s: %s",
|
|
998
|
+
msg_id,
|
|
999
|
+
spend_result.reason,
|
|
1000
|
+
)
|
|
1001
|
+
raise CreditCheckFailed(f"Credit charge failed: {spend_result.reason}")
|
|
1002
|
+
logger.info(
|
|
1003
|
+
"Credit charged successfully for message %s (account %s)",
|
|
1004
|
+
msg_id,
|
|
1005
|
+
account.cache_key(),
|
|
1006
|
+
)
|
|
1007
|
+
except CreditCheckFailed:
|
|
1008
|
+
# Re-raise CreditCheckFailed as-is
|
|
1009
|
+
raise
|
|
1010
|
+
except Exception as exc: # pragma: no cover - provider failure is rare
|
|
1011
|
+
logger.error(
|
|
1012
|
+
"Credit charge error for message %s: %s",
|
|
1013
|
+
msg_id,
|
|
1014
|
+
exc,
|
|
1015
|
+
)
|
|
1016
|
+
raise CreditCheckFailed(str(exc)) from exc
|
|
1017
|
+
|
|
1018
|
+
async def _enforce_credit_policy(self, msg: MessageT) -> None:
|
|
1019
|
+
"""Ensure external credit policy allows processing of this message."""
|
|
1020
|
+
msg_id = getattr(msg, "message_id", "unknown")
|
|
1021
|
+
|
|
1022
|
+
# Get resource monitor from instance or message metadata
|
|
1023
|
+
resource_monitor = self._get_resource_monitor(msg)
|
|
1024
|
+
|
|
1025
|
+
# Determine source for logging
|
|
1026
|
+
monitor_source = self._get_resource_monitor_source(
|
|
1027
|
+
self.resource_monitor is not None, resource_monitor is not None
|
|
1028
|
+
)
|
|
1029
|
+
|
|
1030
|
+
logger.debug(
|
|
1031
|
+
f"[CREDIT] Policy check for message {msg_id}: resource_monitor={resource_monitor is not None}, source={monitor_source}"
|
|
1032
|
+
)
|
|
1033
|
+
|
|
1034
|
+
if not resource_monitor:
|
|
1035
|
+
logger.debug(f"[CREDIT] NO RESOURCE MONITOR for message {msg_id} - skipping credit enforcement")
|
|
1036
|
+
return
|
|
1037
|
+
|
|
1038
|
+
credit_provider = getattr(resource_monitor, "credit_provider", None)
|
|
1039
|
+
logger.debug(
|
|
1040
|
+
f"[CREDIT] Provider status: {credit_provider is not None}, type={type(credit_provider).__name__ if credit_provider else 'None'}"
|
|
1041
|
+
)
|
|
1042
|
+
|
|
1043
|
+
if not credit_provider:
|
|
1044
|
+
logger.debug("[CREDIT] No credit provider - skipping credit enforcement")
|
|
1045
|
+
return
|
|
1046
|
+
|
|
1047
|
+
envelope = self._resolve_credit_envelope(msg)
|
|
1048
|
+
if envelope is None:
|
|
1049
|
+
# CRITICAL: Credit provider is active but no credit metadata attached to message
|
|
1050
|
+
channel_id = getattr(msg, "channel_id", "unknown")
|
|
1051
|
+
logger.critical(
|
|
1052
|
+
f"[CREDIT] ENFORCEMENT SKIPPED: No credit envelope for message {msg_id} in channel {channel_id}. "
|
|
1053
|
+
f"Credit provider IS active but message has no credit metadata attached!"
|
|
1054
|
+
)
|
|
1055
|
+
return
|
|
1056
|
+
|
|
1057
|
+
account, context = envelope
|
|
1058
|
+
|
|
1059
|
+
# Check if user role should bypass credit checks (ADMIN+)
|
|
1060
|
+
user_role = context.user_role
|
|
1061
|
+
if user_role in ["ADMIN", "AUTHORITY", "SYSTEM_ADMIN", "SERVICE_ACCOUNT"]:
|
|
1062
|
+
logger.info(f"[CREDIT] User role {user_role} bypasses credit check for message {msg_id}")
|
|
1063
|
+
return
|
|
1064
|
+
|
|
1065
|
+
logger.debug(f"[CREDIT] Enforcement starting for account {account.cache_key()}, role={user_role}")
|
|
1066
|
+
|
|
1067
|
+
await self._check_and_charge_credit(resource_monitor, account, context, msg)
|
|
1068
|
+
|
|
1069
|
+
def _resolve_credit_envelope(self, msg: MessageT) -> Optional[Tuple[CreditAccount, CreditContext]]:
|
|
1070
|
+
"""Extract credit account/context metadata from the message."""
|
|
1071
|
+
|
|
1072
|
+
raw_account: Any = getattr(msg, "credit_account", None)
|
|
1073
|
+
raw_context: Any = getattr(msg, "credit_context", None)
|
|
1074
|
+
|
|
1075
|
+
if raw_account is None:
|
|
1076
|
+
envelope = getattr(msg, "credit_envelope", None)
|
|
1077
|
+
if isinstance(envelope, dict):
|
|
1078
|
+
raw_account = envelope.get("account")
|
|
1079
|
+
raw_context = envelope.get("context")
|
|
1080
|
+
|
|
1081
|
+
if raw_account is None:
|
|
1082
|
+
return None
|
|
1083
|
+
|
|
1084
|
+
account = raw_account if isinstance(raw_account, CreditAccount) else CreditAccount(**raw_account)
|
|
1085
|
+
|
|
1086
|
+
context: CreditContext
|
|
1087
|
+
if raw_context is None:
|
|
1088
|
+
context = CreditContext()
|
|
1089
|
+
elif isinstance(raw_context, CreditContext):
|
|
1090
|
+
context = raw_context
|
|
1091
|
+
else:
|
|
1092
|
+
context = CreditContext(**raw_context)
|
|
1093
|
+
|
|
1094
|
+
return account, context
|
|
1095
|
+
|
|
1096
|
+
def _should_log_credit_event(self, key: str, *, ttl_seconds: float = 60.0) -> bool:
|
|
1097
|
+
"""Throttle credit-related log messages to avoid audit spam."""
|
|
1098
|
+
|
|
1099
|
+
now = self._current_timestamp()
|
|
1100
|
+
last_logged = self._credit_log_cache.get(key)
|
|
1101
|
+
if last_logged is not None and now - last_logged < ttl_seconds:
|
|
1102
|
+
return False
|
|
1103
|
+
self._credit_log_cache[key] = now
|
|
1104
|
+
return True
|
|
1105
|
+
|
|
1106
|
+
def _current_timestamp(self) -> float:
|
|
1107
|
+
if self.time_service:
|
|
1108
|
+
return self.time_service.now().timestamp()
|
|
1109
|
+
return time.time()
|
|
1110
|
+
|
|
1111
|
+
async def _should_process_message(self, msg: MessageT) -> bool:
|
|
1112
|
+
"""Check if this observer should process the message - to be overridden by subclasses."""
|
|
1113
|
+
return True # Default: process all messages
|
|
1114
|
+
|
|
1115
|
+
async def _get_user_consent_stream(self, user_id: str) -> Optional[str]:
|
|
1116
|
+
"""
|
|
1117
|
+
Get user's consent stream for privacy handling.
|
|
1118
|
+
|
|
1119
|
+
Returns consent stream or None if not found.
|
|
1120
|
+
"""
|
|
1121
|
+
try:
|
|
1122
|
+
# Try to get consent from consent service if available
|
|
1123
|
+
if hasattr(self, "consent_service") and self.consent_service:
|
|
1124
|
+
try:
|
|
1125
|
+
consent = await self.consent_service.get_consent(user_id)
|
|
1126
|
+
return consent.stream.value if consent else None
|
|
1127
|
+
except Exception:
|
|
1128
|
+
return None
|
|
1129
|
+
|
|
1130
|
+
# Try to get from filter service if available
|
|
1131
|
+
if hasattr(self, "filter_service") and self.filter_service:
|
|
1132
|
+
if hasattr(self.filter_service, "_config") and self.filter_service._config:
|
|
1133
|
+
if user_id in self.filter_service._config.user_profiles:
|
|
1134
|
+
profile = self.filter_service._config.user_profiles[user_id]
|
|
1135
|
+
consent_stream_value: str = profile.consent_stream
|
|
1136
|
+
return consent_stream_value
|
|
1137
|
+
|
|
1138
|
+
return None
|
|
1139
|
+
except Exception as e:
|
|
1140
|
+
logger.debug(f"Could not get consent stream for {user_id}: {e}")
|
|
1141
|
+
return None
|