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,1777 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Main agent processor that coordinates all processing activities.
|
|
3
|
+
Uses v1 schemas and integrates state management.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import asyncio
|
|
7
|
+
import logging
|
|
8
|
+
from datetime import datetime, timedelta
|
|
9
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
from ciris_engine.logic import persistence
|
|
12
|
+
from ciris_engine.logic.config import ConfigAccessor
|
|
13
|
+
from ciris_engine.logic.processors.core.thought_processor import ThoughtProcessor
|
|
14
|
+
from ciris_engine.logic.processors.support.processing_queue import ProcessingQueueItem
|
|
15
|
+
from ciris_engine.logic.utils.context_utils import build_dispatch_context
|
|
16
|
+
from ciris_engine.logic.utils.shutdown_manager import (
|
|
17
|
+
get_global_shutdown_reason,
|
|
18
|
+
is_global_shutdown_requested,
|
|
19
|
+
request_global_shutdown,
|
|
20
|
+
)
|
|
21
|
+
from ciris_engine.protocols.pipeline_control import SingleStepResult
|
|
22
|
+
from ciris_engine.schemas.processors.base import ProcessorMetrics, ProcessorServices
|
|
23
|
+
from ciris_engine.schemas.processors.context import ProcessorContext
|
|
24
|
+
from ciris_engine.schemas.processors.main import MainProcessorMetrics, ProcessingRoundResult
|
|
25
|
+
from ciris_engine.schemas.processors.state import StateTransitionRecord
|
|
26
|
+
from ciris_engine.schemas.processors.states import AgentState
|
|
27
|
+
from ciris_engine.schemas.runtime.core import AgentIdentityRoot
|
|
28
|
+
from ciris_engine.schemas.runtime.enums import ThoughtStatus
|
|
29
|
+
from ciris_engine.schemas.runtime.models import Thought
|
|
30
|
+
from ciris_engine.schemas.services.runtime_control import PipelineState
|
|
31
|
+
from ciris_engine.schemas.telemetry.core import (
|
|
32
|
+
CorrelationType,
|
|
33
|
+
ServiceCorrelation,
|
|
34
|
+
ServiceCorrelationStatus,
|
|
35
|
+
ServiceResponseData,
|
|
36
|
+
TraceContext,
|
|
37
|
+
)
|
|
38
|
+
from ciris_engine.schemas.types import JSONDict
|
|
39
|
+
|
|
40
|
+
if TYPE_CHECKING:
|
|
41
|
+
from ciris_engine.logic.infrastructure.handlers.action_dispatcher import ActionDispatcher
|
|
42
|
+
|
|
43
|
+
from ciris_engine.logic.processors.states.dream_processor import DreamProcessor
|
|
44
|
+
from ciris_engine.logic.processors.states.play_processor import PlayProcessor
|
|
45
|
+
from ciris_engine.logic.processors.states.shutdown_processor import ShutdownProcessor
|
|
46
|
+
from ciris_engine.logic.processors.states.solitude_processor import SolitudeProcessor
|
|
47
|
+
from ciris_engine.logic.processors.states.wakeup_processor import WakeupProcessor
|
|
48
|
+
from ciris_engine.logic.processors.states.work_processor import WorkProcessor
|
|
49
|
+
from ciris_engine.logic.processors.support.state_manager import StateManager
|
|
50
|
+
from ciris_engine.protocols.services.lifecycle.time import TimeServiceProtocol
|
|
51
|
+
from ciris_engine.schemas.config.cognitive_state_behaviors import CognitiveStateBehaviors
|
|
52
|
+
|
|
53
|
+
logger = logging.getLogger(__name__)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class AgentProcessor:
|
|
57
|
+
"""
|
|
58
|
+
Main agent processor that orchestrates task processing, thought generation,
|
|
59
|
+
and state management using v1 schemas.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
app_config: ConfigAccessor,
|
|
65
|
+
agent_identity: AgentIdentityRoot,
|
|
66
|
+
thought_processor: ThoughtProcessor,
|
|
67
|
+
action_dispatcher: "ActionDispatcher",
|
|
68
|
+
services: ProcessorServices,
|
|
69
|
+
startup_channel_id: str,
|
|
70
|
+
time_service: TimeServiceProtocol,
|
|
71
|
+
runtime: Optional[Any] = None,
|
|
72
|
+
agent_occurrence_id: str = "default",
|
|
73
|
+
cognitive_behaviors: Optional[CognitiveStateBehaviors] = None,
|
|
74
|
+
) -> None:
|
|
75
|
+
"""Initialize the agent processor with v1 configuration.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
app_config: Configuration accessor
|
|
79
|
+
agent_identity: Agent identity root
|
|
80
|
+
thought_processor: Thought processor instance
|
|
81
|
+
action_dispatcher: Action dispatcher instance
|
|
82
|
+
services: Processor services container
|
|
83
|
+
startup_channel_id: Channel ID for startup messages
|
|
84
|
+
time_service: Time service for timestamps
|
|
85
|
+
runtime: Runtime reference for preload tasks
|
|
86
|
+
agent_occurrence_id: Occurrence ID for multi-instance support
|
|
87
|
+
cognitive_behaviors: Template-driven cognitive state behaviors config.
|
|
88
|
+
Controls wakeup/shutdown/play/dream/solitude state transitions.
|
|
89
|
+
See FSD/COGNITIVE_STATE_BEHAVIORS.md for details.
|
|
90
|
+
"""
|
|
91
|
+
# Allow empty string for startup_channel_id - will be resolved dynamically
|
|
92
|
+
if startup_channel_id is None:
|
|
93
|
+
raise ValueError("startup_channel_id cannot be None (empty string is allowed)")
|
|
94
|
+
self.app_config = app_config
|
|
95
|
+
self.agent_identity = agent_identity
|
|
96
|
+
self.thought_processor = thought_processor
|
|
97
|
+
self._action_dispatcher = action_dispatcher # Store internally
|
|
98
|
+
|
|
99
|
+
# Store services directly - type-safe ProcessorServices
|
|
100
|
+
self.services: ProcessorServices = services
|
|
101
|
+
self.startup_channel_id = startup_channel_id
|
|
102
|
+
self.runtime = runtime # Store runtime reference for preload tasks
|
|
103
|
+
self._time_service = time_service # Store injected time service
|
|
104
|
+
self.agent_occurrence_id = agent_occurrence_id # Store occurrence ID for multi-instance support
|
|
105
|
+
|
|
106
|
+
# Store cognitive behaviors for access by state processors
|
|
107
|
+
self.cognitive_behaviors = cognitive_behaviors or CognitiveStateBehaviors()
|
|
108
|
+
|
|
109
|
+
# Initialize state manager with cognitive behaviors config
|
|
110
|
+
time_service_from_services = services.time_service or time_service
|
|
111
|
+
self.state_manager = StateManager(
|
|
112
|
+
time_service=time_service_from_services,
|
|
113
|
+
initial_state=AgentState.SHUTDOWN,
|
|
114
|
+
cognitive_behaviors=self.cognitive_behaviors,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Initialize specialized processors, passing the standard services container
|
|
118
|
+
self.wakeup_processor = WakeupProcessor(
|
|
119
|
+
config_accessor=app_config,
|
|
120
|
+
thought_processor=thought_processor,
|
|
121
|
+
action_dispatcher=self._action_dispatcher,
|
|
122
|
+
services=services,
|
|
123
|
+
startup_channel_id=startup_channel_id,
|
|
124
|
+
time_service=time_service,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
self.work_processor = WorkProcessor(
|
|
128
|
+
config_accessor=app_config,
|
|
129
|
+
thought_processor=thought_processor,
|
|
130
|
+
action_dispatcher=self._action_dispatcher,
|
|
131
|
+
services=services,
|
|
132
|
+
startup_channel_id=startup_channel_id,
|
|
133
|
+
agent_occurrence_id=agent_occurrence_id,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
self.play_processor = PlayProcessor(
|
|
137
|
+
config_accessor=app_config,
|
|
138
|
+
thought_processor=thought_processor,
|
|
139
|
+
action_dispatcher=self._action_dispatcher,
|
|
140
|
+
services=services,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
self.solitude_processor = SolitudeProcessor(
|
|
144
|
+
config_accessor=app_config,
|
|
145
|
+
thought_processor=thought_processor,
|
|
146
|
+
action_dispatcher=self._action_dispatcher,
|
|
147
|
+
services=services,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Enhanced dream processor with self-configuration and memory consolidation
|
|
151
|
+
# Cast services for type safety
|
|
152
|
+
from typing import cast
|
|
153
|
+
|
|
154
|
+
from ciris_engine.logic.registries.base import ServiceRegistry
|
|
155
|
+
from ciris_engine.logic.runtime.identity_manager import IdentityManager
|
|
156
|
+
|
|
157
|
+
service_registry_typed = cast(ServiceRegistry, services.service_registry) if services.service_registry else None
|
|
158
|
+
identity_manager_typed = cast(IdentityManager, services.identity_manager) if services.identity_manager else None
|
|
159
|
+
|
|
160
|
+
self.dream_processor = DreamProcessor(
|
|
161
|
+
config_accessor=app_config,
|
|
162
|
+
thought_processor=thought_processor,
|
|
163
|
+
action_dispatcher=self._action_dispatcher,
|
|
164
|
+
services=services,
|
|
165
|
+
service_registry=service_registry_typed,
|
|
166
|
+
identity_manager=identity_manager_typed,
|
|
167
|
+
startup_channel_id=startup_channel_id,
|
|
168
|
+
cirisnode_url="https://localhost:8001", # Default since cirisnode config not in essential
|
|
169
|
+
agent_occurrence_id=agent_occurrence_id,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Shutdown processor for graceful shutdown negotiation
|
|
173
|
+
# Pass cognitive_behaviors for conditional/instant shutdown modes
|
|
174
|
+
self.shutdown_processor = ShutdownProcessor(
|
|
175
|
+
config_accessor=app_config,
|
|
176
|
+
thought_processor=thought_processor,
|
|
177
|
+
action_dispatcher=self._action_dispatcher,
|
|
178
|
+
services=services,
|
|
179
|
+
time_service=time_service,
|
|
180
|
+
runtime=runtime,
|
|
181
|
+
agent_occurrence_id=agent_occurrence_id,
|
|
182
|
+
cognitive_behaviors=self.cognitive_behaviors,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Map states to processors
|
|
186
|
+
self.state_processors = {
|
|
187
|
+
AgentState.WAKEUP: self.wakeup_processor,
|
|
188
|
+
AgentState.WORK: self.work_processor,
|
|
189
|
+
AgentState.PLAY: self.play_processor,
|
|
190
|
+
AgentState.SOLITUDE: self.solitude_processor,
|
|
191
|
+
AgentState.SHUTDOWN: self.shutdown_processor,
|
|
192
|
+
AgentState.DREAM: self.dream_processor,
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
# Processing control
|
|
196
|
+
self.current_round_number = 0
|
|
197
|
+
self._stop_event: Optional[asyncio.Event] = None
|
|
198
|
+
self._processing_task: Optional[asyncio.Task[Any]] = None
|
|
199
|
+
|
|
200
|
+
# Pause/resume control for single-stepping
|
|
201
|
+
self._is_paused = False
|
|
202
|
+
self._pause_event: Optional[asyncio.Event] = None
|
|
203
|
+
self._single_step_mode = False
|
|
204
|
+
|
|
205
|
+
# Initialize pipeline controller for single-step debugging
|
|
206
|
+
from ciris_engine.protocols.pipeline_control import PipelineController
|
|
207
|
+
|
|
208
|
+
self._pipeline_controller = PipelineController(is_paused=False, main_processor=self)
|
|
209
|
+
|
|
210
|
+
# Track processing time for thoughts
|
|
211
|
+
self._thought_processing_callback: Optional[Any] = None # Callback for thought timing
|
|
212
|
+
|
|
213
|
+
logger.info("AgentProcessor initialized with v1 schemas and modular processors")
|
|
214
|
+
|
|
215
|
+
def _get_service(self, key: str) -> Any:
|
|
216
|
+
"""Get a service from the ProcessorServices container."""
|
|
217
|
+
return getattr(self.services, key, None)
|
|
218
|
+
|
|
219
|
+
def _load_preload_tasks(self) -> None:
|
|
220
|
+
"""Load preload tasks after successful WORK state transition."""
|
|
221
|
+
try:
|
|
222
|
+
if self.runtime and hasattr(self.runtime, "get_preload_tasks"):
|
|
223
|
+
preload_tasks = self.runtime.get_preload_tasks()
|
|
224
|
+
if preload_tasks:
|
|
225
|
+
logger.info(f"Loading {len(preload_tasks)} preload tasks after WORK state transition")
|
|
226
|
+
from ciris_engine.logic.processors.support.task_manager import TaskManager
|
|
227
|
+
|
|
228
|
+
time_service = self._get_service("time_service")
|
|
229
|
+
tm = TaskManager(time_service=time_service, agent_occurrence_id=self.agent_occurrence_id)
|
|
230
|
+
for desc in preload_tasks:
|
|
231
|
+
try:
|
|
232
|
+
tm.create_task(
|
|
233
|
+
description=desc,
|
|
234
|
+
channel_id=self.startup_channel_id,
|
|
235
|
+
context={"channel_id": self.startup_channel_id},
|
|
236
|
+
)
|
|
237
|
+
logger.info(f"Created preload task: {desc}")
|
|
238
|
+
except Exception as e:
|
|
239
|
+
logger.error(f"Error creating preload task '{desc}': {e}", exc_info=True)
|
|
240
|
+
else:
|
|
241
|
+
logger.debug("No preload tasks to load")
|
|
242
|
+
else:
|
|
243
|
+
logger.debug("Runtime does not support preload tasks")
|
|
244
|
+
except Exception as e:
|
|
245
|
+
logger.error(f"Error loading preload tasks: {e}", exc_info=True)
|
|
246
|
+
|
|
247
|
+
def _ensure_stop_event(self) -> None:
|
|
248
|
+
"""Ensure stop event is created when needed in async context."""
|
|
249
|
+
if self._stop_event is None:
|
|
250
|
+
try:
|
|
251
|
+
self._stop_event = asyncio.Event()
|
|
252
|
+
except RuntimeError:
|
|
253
|
+
logger.warning("Cannot create stop event outside of async context")
|
|
254
|
+
|
|
255
|
+
@property
|
|
256
|
+
def action_dispatcher(self) -> "ActionDispatcher":
|
|
257
|
+
return self._action_dispatcher
|
|
258
|
+
|
|
259
|
+
@action_dispatcher.setter
|
|
260
|
+
def action_dispatcher(self, new_dispatcher: "ActionDispatcher") -> None:
|
|
261
|
+
logger.info(f"AgentProcessor's action_dispatcher is being updated to: {new_dispatcher}")
|
|
262
|
+
self._action_dispatcher = new_dispatcher
|
|
263
|
+
# Propagate the new dispatcher to sub-processors
|
|
264
|
+
# Ensure sub-processors have an 'action_dispatcher' attribute to be updated
|
|
265
|
+
sub_processors_to_update = [
|
|
266
|
+
getattr(self, "wakeup_processor", None),
|
|
267
|
+
getattr(self, "work_processor", None),
|
|
268
|
+
getattr(self, "play_processor", None),
|
|
269
|
+
getattr(self, "solitude_processor", None),
|
|
270
|
+
]
|
|
271
|
+
for sub_processor in sub_processors_to_update:
|
|
272
|
+
if sub_processor and hasattr(sub_processor, "action_dispatcher"):
|
|
273
|
+
logger.info(f"Updating action_dispatcher for {sub_processor.__class__.__name__}")
|
|
274
|
+
sub_processor.action_dispatcher = new_dispatcher
|
|
275
|
+
elif sub_processor:
|
|
276
|
+
logger.warning(
|
|
277
|
+
f"{sub_processor.__class__.__name__} does not have an 'action_dispatcher' attribute to update."
|
|
278
|
+
)
|
|
279
|
+
logger.info("AgentProcessor's action_dispatcher updated and propagated if applicable.")
|
|
280
|
+
|
|
281
|
+
async def start_processing(self, num_rounds: Optional[int] = None) -> None:
|
|
282
|
+
"""Start the main agent processing loop."""
|
|
283
|
+
if self._processing_task is not None and not self._processing_task.done():
|
|
284
|
+
logger.warning("Processing is already running")
|
|
285
|
+
return
|
|
286
|
+
|
|
287
|
+
# Track start time for uptime calculation
|
|
288
|
+
self._start_time = datetime.now()
|
|
289
|
+
|
|
290
|
+
self._ensure_stop_event()
|
|
291
|
+
if self._stop_event is not None:
|
|
292
|
+
self._stop_event.clear()
|
|
293
|
+
logger.info(f"Starting agent processing (rounds: {num_rounds or 'infinite'})")
|
|
294
|
+
|
|
295
|
+
# Determine startup target state based on cognitive behaviors
|
|
296
|
+
# When wakeup is bypassed, transition directly to WORK (partnership model)
|
|
297
|
+
startup_state = self.state_manager.startup_target_state
|
|
298
|
+
wakeup_bypassed = self.state_manager.wakeup_bypassed
|
|
299
|
+
|
|
300
|
+
if wakeup_bypassed:
|
|
301
|
+
logger.info(
|
|
302
|
+
f"Wakeup ceremony bypassed (cognitive_behaviors.wakeup.enabled=False). "
|
|
303
|
+
f"Rationale: {self.cognitive_behaviors.wakeup.rationale or 'Not specified'}"
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# Transition from SHUTDOWN to startup state (WAKEUP or WORK)
|
|
307
|
+
if self.state_manager.get_state() == AgentState.SHUTDOWN:
|
|
308
|
+
if not await self.state_manager.transition_to(startup_state):
|
|
309
|
+
logger.error(f"Failed to transition from SHUTDOWN to {startup_state.value} state")
|
|
310
|
+
return
|
|
311
|
+
elif self.state_manager.get_state() != startup_state:
|
|
312
|
+
logger.warning(f"Unexpected state {self.state_manager.get_state()} when starting processing")
|
|
313
|
+
if not await self.state_manager.transition_to(startup_state):
|
|
314
|
+
logger.error(
|
|
315
|
+
f"Failed to transition from {self.state_manager.get_state()} to {startup_state.value} state"
|
|
316
|
+
)
|
|
317
|
+
return
|
|
318
|
+
|
|
319
|
+
# Skip wakeup sequence if bypassed
|
|
320
|
+
if wakeup_bypassed:
|
|
321
|
+
logger.info("✓ Wakeup bypassed - proceeding directly to WORK state")
|
|
322
|
+
self.state_manager.update_state_metadata("wakeup_complete", True)
|
|
323
|
+
self.state_manager.update_state_metadata("wakeup_bypassed", True)
|
|
324
|
+
else:
|
|
325
|
+
# Full wakeup ceremony
|
|
326
|
+
self.wakeup_processor.initialize()
|
|
327
|
+
|
|
328
|
+
wakeup_complete = False
|
|
329
|
+
wakeup_round = 0
|
|
330
|
+
|
|
331
|
+
while (
|
|
332
|
+
not wakeup_complete
|
|
333
|
+
and not (self._stop_event is not None and self._stop_event.is_set())
|
|
334
|
+
and (num_rounds is None or self.current_round_number < num_rounds)
|
|
335
|
+
):
|
|
336
|
+
logger.info(f"Wakeup round {wakeup_round}")
|
|
337
|
+
|
|
338
|
+
wakeup_result = await self.wakeup_processor.process(wakeup_round)
|
|
339
|
+
wakeup_complete = wakeup_result.wakeup_complete
|
|
340
|
+
|
|
341
|
+
# Check if wakeup failed (any task failed)
|
|
342
|
+
if hasattr(wakeup_result, "errors") and wakeup_result.errors > 0:
|
|
343
|
+
logger.error(f"Wakeup failed with {wakeup_result.errors} errors - transitioning to SHUTDOWN")
|
|
344
|
+
if not await self.state_manager.transition_to(AgentState.SHUTDOWN):
|
|
345
|
+
logger.error("Failed to transition to SHUTDOWN state after wakeup failure")
|
|
346
|
+
await self.stop_processing()
|
|
347
|
+
return
|
|
348
|
+
|
|
349
|
+
if not wakeup_complete:
|
|
350
|
+
_thoughts_processed = await self._process_pending_thoughts_async()
|
|
351
|
+
|
|
352
|
+
logger.info(f"Wakeup round {wakeup_round}: {wakeup_result.thoughts_processed} thoughts processed")
|
|
353
|
+
|
|
354
|
+
# Use shorter delay for mock LLM
|
|
355
|
+
llm_service = self._get_service("llm_service")
|
|
356
|
+
is_mock_llm = llm_service and type(llm_service).__name__ == "MockLLMService"
|
|
357
|
+
round_delay = 0.1 if is_mock_llm else 5.0
|
|
358
|
+
await asyncio.sleep(round_delay)
|
|
359
|
+
else:
|
|
360
|
+
logger.info("✓ Wakeup sequence completed successfully!")
|
|
361
|
+
|
|
362
|
+
wakeup_round += 1
|
|
363
|
+
self.current_round_number += 1
|
|
364
|
+
|
|
365
|
+
if not wakeup_complete:
|
|
366
|
+
logger.error(
|
|
367
|
+
f"Wakeup did not complete within {num_rounds or 'infinite'} rounds - transitioning to SHUTDOWN"
|
|
368
|
+
)
|
|
369
|
+
# Transition to SHUTDOWN state since wakeup failed
|
|
370
|
+
if not await self.state_manager.transition_to(AgentState.SHUTDOWN):
|
|
371
|
+
logger.error("Failed to transition to SHUTDOWN state after wakeup failure")
|
|
372
|
+
await self.stop_processing()
|
|
373
|
+
return
|
|
374
|
+
|
|
375
|
+
logger.info("Attempting to transition from WAKEUP to WORK state...")
|
|
376
|
+
if not await self.state_manager.transition_to(AgentState.WORK):
|
|
377
|
+
logger.error("Failed to transition to WORK state after wakeup")
|
|
378
|
+
await self.stop_processing()
|
|
379
|
+
return
|
|
380
|
+
|
|
381
|
+
logger.info("Successfully transitioned to WORK state")
|
|
382
|
+
self.state_manager.update_state_metadata("wakeup_complete", True)
|
|
383
|
+
|
|
384
|
+
logger.info("Loading preload tasks...")
|
|
385
|
+
self._load_preload_tasks()
|
|
386
|
+
|
|
387
|
+
# Schedule first dream session
|
|
388
|
+
logger.info("Scheduling initial dream session...")
|
|
389
|
+
await self._schedule_initial_dream()
|
|
390
|
+
|
|
391
|
+
if hasattr(self, "runtime") and self.runtime is not None and hasattr(self.runtime, "start_interactive_console"):
|
|
392
|
+
print("[STATE] Initializing interactive console for user input...")
|
|
393
|
+
try:
|
|
394
|
+
await self.runtime.start_interactive_console()
|
|
395
|
+
except Exception as e:
|
|
396
|
+
logger.error(f"Error initializing interactive console: {e}")
|
|
397
|
+
|
|
398
|
+
logger.info("Initializing work processor...")
|
|
399
|
+
self.work_processor.initialize()
|
|
400
|
+
logger.info("Work processor initialized successfully")
|
|
401
|
+
|
|
402
|
+
logger.info("Creating processing loop task...")
|
|
403
|
+
self._processing_task = asyncio.create_task(self._processing_loop(num_rounds))
|
|
404
|
+
logger.info("Processing loop task created")
|
|
405
|
+
|
|
406
|
+
try:
|
|
407
|
+
await self._processing_task
|
|
408
|
+
except asyncio.CancelledError:
|
|
409
|
+
logger.info("Processing task was cancelled")
|
|
410
|
+
raise
|
|
411
|
+
except Exception as e:
|
|
412
|
+
logger.error(f"Processing loop error: {e}", exc_info=True)
|
|
413
|
+
finally:
|
|
414
|
+
if self._stop_event is not None:
|
|
415
|
+
self._stop_event.set()
|
|
416
|
+
|
|
417
|
+
async def _process_pending_thoughts_async(self) -> int:
|
|
418
|
+
"""
|
|
419
|
+
Process all pending thoughts asynchronously with comprehensive error handling.
|
|
420
|
+
This is the key to non-blocking operation - it processes ALL thoughts,
|
|
421
|
+
not just wakeup thoughts.
|
|
422
|
+
"""
|
|
423
|
+
try:
|
|
424
|
+
# Get current state to filter thoughts appropriately
|
|
425
|
+
current_state = self.state_manager.get_state()
|
|
426
|
+
|
|
427
|
+
pending_thoughts = persistence.get_pending_thoughts_for_active_tasks(self.agent_occurrence_id)
|
|
428
|
+
|
|
429
|
+
# If in SHUTDOWN state, only process thoughts for shutdown tasks
|
|
430
|
+
if current_state == AgentState.SHUTDOWN:
|
|
431
|
+
shutdown_thoughts = [
|
|
432
|
+
t for t in pending_thoughts if t.source_task_id and t.source_task_id.startswith("shutdown_")
|
|
433
|
+
]
|
|
434
|
+
pending_thoughts = shutdown_thoughts
|
|
435
|
+
logger.info(f"In SHUTDOWN state - filtering to {len(shutdown_thoughts)} shutdown-related thoughts only")
|
|
436
|
+
|
|
437
|
+
max_active = 10
|
|
438
|
+
if hasattr(self.app_config, "workflow") and self.app_config.workflow:
|
|
439
|
+
max_active = getattr(self.app_config.workflow, "max_active_thoughts", 10)
|
|
440
|
+
|
|
441
|
+
limited_thoughts = pending_thoughts[:max_active]
|
|
442
|
+
|
|
443
|
+
logger.info(
|
|
444
|
+
f"Found {len(pending_thoughts)} PENDING thoughts, processing {len(limited_thoughts)} (max_active_thoughts: {max_active})"
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
if not limited_thoughts:
|
|
448
|
+
return 0
|
|
449
|
+
|
|
450
|
+
processed_count = 0
|
|
451
|
+
failed_count = 0
|
|
452
|
+
|
|
453
|
+
batch_size = 5
|
|
454
|
+
|
|
455
|
+
for i in range(0, len(limited_thoughts), batch_size):
|
|
456
|
+
try:
|
|
457
|
+
batch = limited_thoughts[i : i + batch_size]
|
|
458
|
+
|
|
459
|
+
# Pre-fetch all thoughts in the batch to avoid serialization
|
|
460
|
+
thought_ids = [t.thought_id for t in batch]
|
|
461
|
+
logger.debug(f"[DEBUG TIMING] Pre-fetching {len(thought_ids)} thoughts in batch")
|
|
462
|
+
prefetched_thoughts = await persistence.async_get_thoughts_by_ids(
|
|
463
|
+
thought_ids, self.agent_occurrence_id
|
|
464
|
+
)
|
|
465
|
+
logger.debug(f"[DEBUG TIMING] Pre-fetched {len(prefetched_thoughts)} thoughts")
|
|
466
|
+
|
|
467
|
+
# Pre-fetch batch context data (same for all thoughts)
|
|
468
|
+
logger.debug("[DEBUG TIMING] Pre-fetching batch context data")
|
|
469
|
+
from ciris_engine.logic.context.batch_context import prefetch_batch_context
|
|
470
|
+
|
|
471
|
+
batch_context_data = await prefetch_batch_context(
|
|
472
|
+
memory_service=self._get_service("memory_service"),
|
|
473
|
+
secrets_service=self._get_service("secrets_service"),
|
|
474
|
+
service_registry=self._get_service("service_registry"),
|
|
475
|
+
resource_monitor=self._get_service("resource_monitor"),
|
|
476
|
+
telemetry_service=self._get_service("telemetry_service"),
|
|
477
|
+
runtime=self.runtime,
|
|
478
|
+
)
|
|
479
|
+
logger.debug("[DEBUG TIMING] Pre-fetched batch context data")
|
|
480
|
+
|
|
481
|
+
tasks: List[Any] = []
|
|
482
|
+
for thought in batch:
|
|
483
|
+
try:
|
|
484
|
+
persistence.update_thought_status(
|
|
485
|
+
thought_id=thought.thought_id, status=ThoughtStatus.PROCESSING
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
# Use prefetched thought if available
|
|
489
|
+
full_thought = prefetched_thoughts.get(thought.thought_id, thought)
|
|
490
|
+
task = self._process_single_thought(
|
|
491
|
+
full_thought, prefetched=True, batch_context=batch_context_data
|
|
492
|
+
)
|
|
493
|
+
tasks.append(task)
|
|
494
|
+
except Exception as e:
|
|
495
|
+
logger.error(
|
|
496
|
+
f"Error preparing thought {thought.thought_id} for processing: {e}", exc_info=True
|
|
497
|
+
)
|
|
498
|
+
failed_count += 1
|
|
499
|
+
continue
|
|
500
|
+
|
|
501
|
+
if not tasks:
|
|
502
|
+
continue
|
|
503
|
+
|
|
504
|
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
505
|
+
|
|
506
|
+
for result, thought in zip(results, batch):
|
|
507
|
+
try:
|
|
508
|
+
if isinstance(result, Exception):
|
|
509
|
+
logger.error(f"Error processing thought {thought.thought_id}: {result}")
|
|
510
|
+
persistence.update_thought_status(
|
|
511
|
+
thought_id=thought.thought_id,
|
|
512
|
+
status=ThoughtStatus.FAILED,
|
|
513
|
+
final_action={"error": str(result)},
|
|
514
|
+
)
|
|
515
|
+
failed_count += 1
|
|
516
|
+
else:
|
|
517
|
+
processed_count += 1
|
|
518
|
+
except Exception as e:
|
|
519
|
+
logger.error(f"Error handling result for thought {thought.thought_id}: {e}", exc_info=True)
|
|
520
|
+
failed_count += 1
|
|
521
|
+
|
|
522
|
+
except Exception as e:
|
|
523
|
+
logger.error(f"Error processing thought batch {i//batch_size + 1}: {e}", exc_info=True)
|
|
524
|
+
failed_count += len(batch) if "batch" in locals() else batch_size
|
|
525
|
+
|
|
526
|
+
if failed_count > 0:
|
|
527
|
+
logger.warning(
|
|
528
|
+
f"Thought processing completed with {failed_count} failures out of {len(limited_thoughts)} attempts"
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
return processed_count
|
|
532
|
+
|
|
533
|
+
except Exception as e:
|
|
534
|
+
logger.error(f"CRITICAL: Error in _process_pending_thoughts_async: {e}", exc_info=True)
|
|
535
|
+
return 0
|
|
536
|
+
|
|
537
|
+
async def _process_single_thought(
|
|
538
|
+
self, thought: Thought, prefetched: bool = False, batch_context: Optional[Any] = None
|
|
539
|
+
) -> bool:
|
|
540
|
+
"""Process a single thought and dispatch its action, with comprehensive error handling."""
|
|
541
|
+
logger.info(
|
|
542
|
+
f"[DEBUG TIMING] _process_single_thought START for thought {thought.thought_id} (prefetched={prefetched}, has_batch_context={batch_context is not None})"
|
|
543
|
+
)
|
|
544
|
+
start_time = self._time_service.now()
|
|
545
|
+
trace_id = f"task_{thought.source_task_id or 'unknown'}_{thought.thought_id}"
|
|
546
|
+
span_id = f"agent_processor_{thought.thought_id}"
|
|
547
|
+
|
|
548
|
+
# Create TRACE_SPAN correlation for this thought processing
|
|
549
|
+
trace_context = TraceContext(
|
|
550
|
+
trace_id=trace_id,
|
|
551
|
+
span_id=span_id,
|
|
552
|
+
parent_span_id=None, # Add missing parent_span_id
|
|
553
|
+
span_name="process_single_thought",
|
|
554
|
+
span_kind="internal",
|
|
555
|
+
baggage={
|
|
556
|
+
"thought_id": thought.thought_id,
|
|
557
|
+
"task_id": thought.source_task_id or "",
|
|
558
|
+
"processor_state": self.state_manager.get_state().value,
|
|
559
|
+
},
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
correlation = ServiceCorrelation(
|
|
563
|
+
correlation_id=f"trace_{span_id}_{start_time.timestamp()}",
|
|
564
|
+
correlation_type=CorrelationType.TRACE_SPAN,
|
|
565
|
+
service_type="agent_processor",
|
|
566
|
+
handler_name="AgentProcessor",
|
|
567
|
+
action_type="process_thought",
|
|
568
|
+
created_at=start_time,
|
|
569
|
+
updated_at=start_time,
|
|
570
|
+
timestamp=start_time,
|
|
571
|
+
trace_context=trace_context,
|
|
572
|
+
tags={
|
|
573
|
+
"thought_id": thought.thought_id,
|
|
574
|
+
"task_id": thought.source_task_id or "",
|
|
575
|
+
"component_type": "agent_processor",
|
|
576
|
+
"trace_depth": "1",
|
|
577
|
+
"thought_type": thought.thought_type.value if thought.thought_type else "unknown",
|
|
578
|
+
"processor_state": self.state_manager.get_state().value,
|
|
579
|
+
},
|
|
580
|
+
# Add missing required fields
|
|
581
|
+
request_data=None,
|
|
582
|
+
response_data=None,
|
|
583
|
+
status=ServiceCorrelationStatus.PENDING,
|
|
584
|
+
metric_data=None,
|
|
585
|
+
log_data=None,
|
|
586
|
+
retention_policy="raw",
|
|
587
|
+
ttl_seconds=None,
|
|
588
|
+
parent_correlation_id=None,
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
# Add correlation to track this processing
|
|
592
|
+
persistence.add_correlation(correlation, self._time_service)
|
|
593
|
+
|
|
594
|
+
try:
|
|
595
|
+
# Create processing queue item
|
|
596
|
+
item = ProcessingQueueItem.from_thought(thought)
|
|
597
|
+
|
|
598
|
+
# Use the current state's processor for fallback-aware processing
|
|
599
|
+
processor = self.state_processors.get(self.state_manager.get_state())
|
|
600
|
+
if processor is None:
|
|
601
|
+
logger.error(f"No processor found for state {self.state_manager.get_state()}")
|
|
602
|
+
persistence.update_thought_status(
|
|
603
|
+
thought_id=thought.thought_id,
|
|
604
|
+
status=ThoughtStatus.FAILED,
|
|
605
|
+
final_action={"error": f"No processor for state {self.state_manager.get_state()}"},
|
|
606
|
+
)
|
|
607
|
+
# Update correlation with failure
|
|
608
|
+
end_time = self._time_service.now()
|
|
609
|
+
correlation.response_data = ServiceResponseData(
|
|
610
|
+
success=False,
|
|
611
|
+
error_message=f"No processor for state {self.state_manager.get_state()}",
|
|
612
|
+
execution_time_ms=(end_time - start_time).total_seconds() * 1000,
|
|
613
|
+
response_timestamp=end_time,
|
|
614
|
+
# Add missing required fields
|
|
615
|
+
result_summary=None,
|
|
616
|
+
result_type=None,
|
|
617
|
+
result_size=None,
|
|
618
|
+
error_type="ProcessorNotFound",
|
|
619
|
+
error_traceback=None,
|
|
620
|
+
tokens_used=None,
|
|
621
|
+
memory_bytes=None,
|
|
622
|
+
)
|
|
623
|
+
correlation.updated_at = end_time
|
|
624
|
+
persistence.update_correlation(correlation.correlation_id, correlation, self._time_service)
|
|
625
|
+
return False
|
|
626
|
+
|
|
627
|
+
# Use fallback-aware process_thought_item
|
|
628
|
+
try:
|
|
629
|
+
logger.debug(f"Calling processor.process_thought_item for thought {thought.thought_id}")
|
|
630
|
+
context = ProcessorContext(
|
|
631
|
+
origin="wakeup_async",
|
|
632
|
+
prefetched_thought=thought if prefetched else None,
|
|
633
|
+
batch_context=batch_context,
|
|
634
|
+
)
|
|
635
|
+
result = await processor.process_thought_item(item, context=context.model_dump())
|
|
636
|
+
except Exception as e:
|
|
637
|
+
logger.error(
|
|
638
|
+
f"Error in processor.process_thought_item for thought {thought.thought_id}: {e}", exc_info=True
|
|
639
|
+
)
|
|
640
|
+
persistence.update_thought_status(
|
|
641
|
+
thought_id=thought.thought_id,
|
|
642
|
+
status=ThoughtStatus.FAILED,
|
|
643
|
+
final_action={"error": f"Processor error: {e}"},
|
|
644
|
+
)
|
|
645
|
+
# Update correlation with failure
|
|
646
|
+
end_time = self._time_service.now()
|
|
647
|
+
correlation.response_data = ServiceResponseData(
|
|
648
|
+
success=False,
|
|
649
|
+
error_message=f"Processor error: {e}",
|
|
650
|
+
execution_time_ms=(end_time - start_time).total_seconds() * 1000,
|
|
651
|
+
response_timestamp=end_time,
|
|
652
|
+
# Add missing required fields
|
|
653
|
+
result_summary=None,
|
|
654
|
+
result_type=None,
|
|
655
|
+
result_size=None,
|
|
656
|
+
error_type=type(e).__name__,
|
|
657
|
+
error_traceback=None,
|
|
658
|
+
tokens_used=None,
|
|
659
|
+
memory_bytes=None,
|
|
660
|
+
)
|
|
661
|
+
correlation.updated_at = end_time
|
|
662
|
+
persistence.update_correlation(correlation.correlation_id, correlation, self._time_service)
|
|
663
|
+
return False
|
|
664
|
+
|
|
665
|
+
if result:
|
|
666
|
+
try:
|
|
667
|
+
# Get the task for context
|
|
668
|
+
task = persistence.get_task_by_id(thought.source_task_id, self.agent_occurrence_id)
|
|
669
|
+
|
|
670
|
+
# Extract conscience result if available
|
|
671
|
+
conscience_result = getattr(result, "_conscience_result", None)
|
|
672
|
+
|
|
673
|
+
dispatch_context = build_dispatch_context(
|
|
674
|
+
thought=thought,
|
|
675
|
+
time_service=self._time_service,
|
|
676
|
+
task=task,
|
|
677
|
+
app_config=self.app_config,
|
|
678
|
+
round_number=self.current_round_number,
|
|
679
|
+
conscience_result=conscience_result,
|
|
680
|
+
action_type=result.final_action.selected_action if result else None,
|
|
681
|
+
)
|
|
682
|
+
# Services should be accessed via service registry, not passed in context
|
|
683
|
+
# to avoid serialization issues during audit logging
|
|
684
|
+
|
|
685
|
+
await self.action_dispatcher.dispatch(
|
|
686
|
+
action_selection_result=result, thought=thought, dispatch_context=dispatch_context
|
|
687
|
+
)
|
|
688
|
+
return True
|
|
689
|
+
except Exception as e:
|
|
690
|
+
logger.error(
|
|
691
|
+
f"Error in action_dispatcher.dispatch for thought {thought.thought_id}: {e}", exc_info=True
|
|
692
|
+
)
|
|
693
|
+
persistence.update_thought_status(
|
|
694
|
+
thought_id=thought.thought_id,
|
|
695
|
+
status=ThoughtStatus.FAILED,
|
|
696
|
+
final_action={"error": f"Dispatch error: {e}"},
|
|
697
|
+
)
|
|
698
|
+
# Update correlation with dispatch failure
|
|
699
|
+
end_time = self._time_service.now()
|
|
700
|
+
correlation.response_data = ServiceResponseData(
|
|
701
|
+
success=False,
|
|
702
|
+
error_message=f"Dispatch error: {e}",
|
|
703
|
+
execution_time_ms=(end_time - start_time).total_seconds() * 1000,
|
|
704
|
+
response_timestamp=end_time,
|
|
705
|
+
# Add missing required fields
|
|
706
|
+
result_summary=None,
|
|
707
|
+
result_type=None,
|
|
708
|
+
result_size=None,
|
|
709
|
+
error_type=type(e).__name__,
|
|
710
|
+
error_traceback=None,
|
|
711
|
+
tokens_used=None,
|
|
712
|
+
memory_bytes=None,
|
|
713
|
+
)
|
|
714
|
+
correlation.updated_at = end_time
|
|
715
|
+
persistence.update_correlation(correlation.correlation_id, correlation, self._time_service)
|
|
716
|
+
return False
|
|
717
|
+
else:
|
|
718
|
+
try:
|
|
719
|
+
# Check if the thought was already handled (e.g., TASK_COMPLETE)
|
|
720
|
+
updated_thought = await persistence.async_get_thought_by_id(
|
|
721
|
+
thought.thought_id, self.agent_occurrence_id
|
|
722
|
+
)
|
|
723
|
+
if updated_thought and updated_thought.status in [ThoughtStatus.COMPLETED, ThoughtStatus.FAILED]:
|
|
724
|
+
logger.debug(
|
|
725
|
+
f"Thought {thought.thought_id} was already handled with status {updated_thought.status.value}"
|
|
726
|
+
)
|
|
727
|
+
# Update correlation - thought was already handled
|
|
728
|
+
end_time = self._time_service.now()
|
|
729
|
+
correlation.response_data = ServiceResponseData(
|
|
730
|
+
success=True,
|
|
731
|
+
result_summary=f"Thought already handled with status {updated_thought.status.value}",
|
|
732
|
+
execution_time_ms=(end_time - start_time).total_seconds() * 1000,
|
|
733
|
+
response_timestamp=end_time,
|
|
734
|
+
# Add missing required fields
|
|
735
|
+
result_type="already_handled",
|
|
736
|
+
result_size=None,
|
|
737
|
+
error_type=None,
|
|
738
|
+
error_message=None,
|
|
739
|
+
error_traceback=None,
|
|
740
|
+
tokens_used=None,
|
|
741
|
+
memory_bytes=None,
|
|
742
|
+
)
|
|
743
|
+
correlation.updated_at = end_time
|
|
744
|
+
persistence.update_correlation(correlation.correlation_id, correlation, self._time_service)
|
|
745
|
+
return True
|
|
746
|
+
else:
|
|
747
|
+
logger.warning(f"No result from processing thought {thought.thought_id}")
|
|
748
|
+
persistence.update_thought_status(
|
|
749
|
+
thought_id=thought.thought_id,
|
|
750
|
+
status=ThoughtStatus.FAILED,
|
|
751
|
+
final_action={"error": "No processing result and thought not already handled"},
|
|
752
|
+
)
|
|
753
|
+
return False
|
|
754
|
+
except Exception as e:
|
|
755
|
+
logger.error(f"Error checking thought status for {thought.thought_id}: {e}", exc_info=True)
|
|
756
|
+
return False
|
|
757
|
+
except Exception as e:
|
|
758
|
+
logger.error(f"CRITICAL: Unhandled error processing thought {thought.thought_id}: {e}", exc_info=True)
|
|
759
|
+
try:
|
|
760
|
+
persistence.update_thought_status(
|
|
761
|
+
thought_id=thought.thought_id,
|
|
762
|
+
status=ThoughtStatus.FAILED,
|
|
763
|
+
final_action={"error": f"Critical processing error: {e}"},
|
|
764
|
+
)
|
|
765
|
+
except Exception as update_error:
|
|
766
|
+
logger.error(f"Failed to update thought status after critical error: {update_error}", exc_info=True)
|
|
767
|
+
|
|
768
|
+
# Update correlation with critical error
|
|
769
|
+
end_time = self._time_service.now()
|
|
770
|
+
correlation.response_data = ServiceResponseData(
|
|
771
|
+
success=False,
|
|
772
|
+
error_message=f"Critical processing error: {e}",
|
|
773
|
+
execution_time_ms=(end_time - start_time).total_seconds() * 1000,
|
|
774
|
+
response_timestamp=end_time,
|
|
775
|
+
# Add missing required fields
|
|
776
|
+
result_summary=None,
|
|
777
|
+
result_type=None,
|
|
778
|
+
result_size=None,
|
|
779
|
+
error_type="CriticalError",
|
|
780
|
+
error_traceback=None,
|
|
781
|
+
tokens_used=None,
|
|
782
|
+
memory_bytes=None,
|
|
783
|
+
)
|
|
784
|
+
correlation.updated_at = end_time
|
|
785
|
+
correlation.tags["task_status"] = "FAILED"
|
|
786
|
+
try:
|
|
787
|
+
persistence.update_correlation(correlation.correlation_id, correlation, self._time_service)
|
|
788
|
+
except Exception as corr_error:
|
|
789
|
+
logger.error(f"Failed to update correlation after critical error: {corr_error}")
|
|
790
|
+
raise
|
|
791
|
+
|
|
792
|
+
async def pause_processing(self) -> bool:
|
|
793
|
+
"""
|
|
794
|
+
Pause the agent processor.
|
|
795
|
+
Safe to call even if already paused.
|
|
796
|
+
|
|
797
|
+
Returns:
|
|
798
|
+
True if successfully paused (or already paused), False if error occurred
|
|
799
|
+
"""
|
|
800
|
+
logger.debug(f"[DEBUG] pause_processing() called, current _is_paused: {self._is_paused}")
|
|
801
|
+
|
|
802
|
+
if self._is_paused:
|
|
803
|
+
logger.info("AgentProcessor already paused")
|
|
804
|
+
logger.debug(f"[DEBUG] Returning True from pause_processing, _is_paused: {self._is_paused}")
|
|
805
|
+
return True # Already paused, still in desired state
|
|
806
|
+
|
|
807
|
+
try:
|
|
808
|
+
logger.info("Pausing AgentProcessor")
|
|
809
|
+
self._is_paused = True
|
|
810
|
+
logger.debug(f"[DEBUG] Set _is_paused to True: {self._is_paused}")
|
|
811
|
+
|
|
812
|
+
# Create pause event if needed
|
|
813
|
+
if self._pause_event is None:
|
|
814
|
+
self._pause_event = asyncio.Event()
|
|
815
|
+
|
|
816
|
+
# Update pipeline controller state for paused mode
|
|
817
|
+
self._pipeline_controller.is_paused = True
|
|
818
|
+
# Set step to 1 (START_ROUND) - index 0 in step_order
|
|
819
|
+
self._pipeline_controller._current_step_index = 0
|
|
820
|
+
|
|
821
|
+
# Pipeline controller is always available at self._pipeline_controller
|
|
822
|
+
# No injection needed - components use it directly
|
|
823
|
+
|
|
824
|
+
logger.debug(f"[DEBUG] Successfully paused, final _is_paused: {self._is_paused}")
|
|
825
|
+
return True # Successfully paused
|
|
826
|
+
|
|
827
|
+
except Exception as e:
|
|
828
|
+
logger.error(f"Failed to pause processor: {e}")
|
|
829
|
+
self._is_paused = False # Reset state on error
|
|
830
|
+
return False
|
|
831
|
+
|
|
832
|
+
async def resume_processing(self) -> bool:
|
|
833
|
+
"""
|
|
834
|
+
Resume the agent processor from pause.
|
|
835
|
+
|
|
836
|
+
Returns:
|
|
837
|
+
True if successfully resumed
|
|
838
|
+
"""
|
|
839
|
+
logger.debug(f"[DEBUG] resume_processing() called, current _is_paused: {self._is_paused}")
|
|
840
|
+
|
|
841
|
+
if not self._is_paused:
|
|
842
|
+
logger.info("AgentProcessor not paused")
|
|
843
|
+
logger.debug(f"[DEBUG] Returning False from resume_processing, _is_paused: {self._is_paused}")
|
|
844
|
+
return False
|
|
845
|
+
|
|
846
|
+
logger.info("Resuming AgentProcessor")
|
|
847
|
+
self._is_paused = False
|
|
848
|
+
self._single_step_mode = False
|
|
849
|
+
logger.debug(f"[DEBUG] Set _is_paused to False: {self._is_paused}")
|
|
850
|
+
|
|
851
|
+
# Update pipeline controller state and resume all paused thoughts
|
|
852
|
+
self._pipeline_controller.is_paused = False
|
|
853
|
+
self._pipeline_controller.resume_all()
|
|
854
|
+
|
|
855
|
+
# Signal pause event to continue
|
|
856
|
+
if self._pause_event and isinstance(self._pause_event, asyncio.Event):
|
|
857
|
+
self._pause_event.set()
|
|
858
|
+
|
|
859
|
+
logger.debug(f"[DEBUG] Successfully resumed, final _is_paused: {self._is_paused}")
|
|
860
|
+
return True
|
|
861
|
+
|
|
862
|
+
def is_paused(self) -> bool:
|
|
863
|
+
"""Check if processor is paused."""
|
|
864
|
+
logger.debug(f"[DEBUG] is_paused() called, returning: {self._is_paused}")
|
|
865
|
+
return self._is_paused
|
|
866
|
+
|
|
867
|
+
def set_thought_processing_callback(self, callback: Any) -> None:
|
|
868
|
+
"""Set callback for thought processing time tracking."""
|
|
869
|
+
self._thought_processing_callback = callback
|
|
870
|
+
|
|
871
|
+
async def single_step(self) -> "SingleStepResult":
|
|
872
|
+
"""
|
|
873
|
+
Execute one step point in the PDMA pipeline when paused.
|
|
874
|
+
|
|
875
|
+
FAIL FAST: No fallbacks, no fake data. Either the pipeline controller
|
|
876
|
+
has execute_single_step_point or we fail loudly.
|
|
877
|
+
|
|
878
|
+
Returns:
|
|
879
|
+
SingleStepResult with step execution details
|
|
880
|
+
"""
|
|
881
|
+
logger.info(f"single_step() called, paused: {self._is_paused}")
|
|
882
|
+
|
|
883
|
+
if not self._is_paused:
|
|
884
|
+
raise RuntimeError("Cannot single-step unless processor is paused")
|
|
885
|
+
|
|
886
|
+
if not self._pipeline_controller:
|
|
887
|
+
raise RuntimeError("No pipeline controller available")
|
|
888
|
+
|
|
889
|
+
if not hasattr(self._pipeline_controller, "execute_single_step_point"):
|
|
890
|
+
raise NotImplementedError(
|
|
891
|
+
f"Pipeline controller {type(self._pipeline_controller).__name__} missing execute_single_step_point method. "
|
|
892
|
+
"Single-step functionality requires a proper pipeline controller implementation."
|
|
893
|
+
)
|
|
894
|
+
|
|
895
|
+
# Enable single-step mode
|
|
896
|
+
self._single_step_mode = True
|
|
897
|
+
self._pipeline_controller._single_step_mode = True
|
|
898
|
+
|
|
899
|
+
try:
|
|
900
|
+
logger.info("Executing single step point via pipeline controller")
|
|
901
|
+
step_result = await self._pipeline_controller.execute_single_step_point()
|
|
902
|
+
|
|
903
|
+
if not step_result:
|
|
904
|
+
raise ValueError("Pipeline controller returned None")
|
|
905
|
+
|
|
906
|
+
# Return the typed result directly
|
|
907
|
+
if isinstance(step_result, SingleStepResult):
|
|
908
|
+
return step_result
|
|
909
|
+
else:
|
|
910
|
+
raise ValueError(f"Invalid step result type from pipeline controller: {type(step_result)}")
|
|
911
|
+
|
|
912
|
+
finally:
|
|
913
|
+
# Always disable single-step mode
|
|
914
|
+
self._single_step_mode = False
|
|
915
|
+
if self._pipeline_controller:
|
|
916
|
+
self._pipeline_controller._single_step_mode = False
|
|
917
|
+
|
|
918
|
+
async def stop_processing(self) -> None:
|
|
919
|
+
"""Stop the processing loop gracefully."""
|
|
920
|
+
if self._processing_task is None or self._processing_task.done():
|
|
921
|
+
logger.info("Processing loop is not running")
|
|
922
|
+
return
|
|
923
|
+
|
|
924
|
+
logger.info("Stopping processing loop...")
|
|
925
|
+
if self._stop_event is not None:
|
|
926
|
+
self._stop_event.set()
|
|
927
|
+
|
|
928
|
+
if self.state_manager.get_state() == AgentState.DREAM and self.dream_processor:
|
|
929
|
+
await self.dream_processor.stop_dreaming()
|
|
930
|
+
|
|
931
|
+
for processor in self.state_processors.values():
|
|
932
|
+
try:
|
|
933
|
+
processor.cleanup()
|
|
934
|
+
except Exception as e:
|
|
935
|
+
logger.error(f"Error cleaning up {processor}: {e}")
|
|
936
|
+
|
|
937
|
+
await self.state_manager.transition_to(AgentState.SHUTDOWN)
|
|
938
|
+
|
|
939
|
+
try:
|
|
940
|
+
await asyncio.wait_for(self._processing_task, timeout=10.0)
|
|
941
|
+
logger.info("Processing loop stopped")
|
|
942
|
+
except asyncio.TimeoutError:
|
|
943
|
+
logger.warning("Processing loop did not stop within timeout, cancelling")
|
|
944
|
+
if self._processing_task is not None:
|
|
945
|
+
self._processing_task.cancel()
|
|
946
|
+
try:
|
|
947
|
+
await self._processing_task
|
|
948
|
+
except asyncio.CancelledError:
|
|
949
|
+
logger.info("Processing task cancelled")
|
|
950
|
+
raise
|
|
951
|
+
finally:
|
|
952
|
+
self._processing_task = None
|
|
953
|
+
|
|
954
|
+
async def _check_pause_state(self) -> bool:
|
|
955
|
+
"""
|
|
956
|
+
Check pause state and handle waiting for resume.
|
|
957
|
+
|
|
958
|
+
Returns:
|
|
959
|
+
True if processing should continue, False if should skip this round
|
|
960
|
+
"""
|
|
961
|
+
if not self._is_paused:
|
|
962
|
+
return True
|
|
963
|
+
|
|
964
|
+
logger.debug("Processor is paused, waiting for resume or single-step")
|
|
965
|
+
if self._pause_event and isinstance(self._pause_event, asyncio.Event):
|
|
966
|
+
await self._pause_event.wait()
|
|
967
|
+
# Reset the event for next pause
|
|
968
|
+
self._pause_event.clear()
|
|
969
|
+
else:
|
|
970
|
+
# Safety fallback - wait a bit and check again
|
|
971
|
+
await asyncio.sleep(0.1)
|
|
972
|
+
return False
|
|
973
|
+
return True
|
|
974
|
+
|
|
975
|
+
async def _handle_shutdown_transitions(self, current_state: AgentState) -> bool:
|
|
976
|
+
"""
|
|
977
|
+
Handle shutdown-related state transitions.
|
|
978
|
+
|
|
979
|
+
Args:
|
|
980
|
+
current_state: Current agent state
|
|
981
|
+
|
|
982
|
+
Returns:
|
|
983
|
+
True to continue processing, False to break from loop
|
|
984
|
+
"""
|
|
985
|
+
if current_state == AgentState.SHUTDOWN:
|
|
986
|
+
logger.debug("In SHUTDOWN state, skipping transition checks")
|
|
987
|
+
return True
|
|
988
|
+
|
|
989
|
+
# Check if shutdown has been requested
|
|
990
|
+
if is_global_shutdown_requested():
|
|
991
|
+
shutdown_reason = get_global_shutdown_reason() or "Unknown reason"
|
|
992
|
+
logger.info(f"Global shutdown requested: {shutdown_reason}")
|
|
993
|
+
# Transition to shutdown state if not already there
|
|
994
|
+
if await self.state_manager.can_transition_to(AgentState.SHUTDOWN):
|
|
995
|
+
await self._handle_state_transition(AgentState.SHUTDOWN)
|
|
996
|
+
else:
|
|
997
|
+
logger.error(f"Cannot transition from {current_state} to SHUTDOWN")
|
|
998
|
+
return False
|
|
999
|
+
else:
|
|
1000
|
+
# Check for automatic state transitions only if not shutting down
|
|
1001
|
+
next_state = self.state_manager.should_auto_transition()
|
|
1002
|
+
if next_state:
|
|
1003
|
+
await self._handle_state_transition(next_state)
|
|
1004
|
+
return True
|
|
1005
|
+
|
|
1006
|
+
async def _process_regular_state(
|
|
1007
|
+
self, processor: Any, current_state: AgentState, consecutive_errors: int, max_consecutive_errors: int
|
|
1008
|
+
) -> tuple[int, int, bool]:
|
|
1009
|
+
"""
|
|
1010
|
+
Process regular (non-shutdown) states.
|
|
1011
|
+
|
|
1012
|
+
Args:
|
|
1013
|
+
processor: State processor
|
|
1014
|
+
current_state: Current agent state
|
|
1015
|
+
consecutive_errors: Current consecutive error count
|
|
1016
|
+
max_consecutive_errors: Maximum allowed consecutive errors
|
|
1017
|
+
|
|
1018
|
+
Returns:
|
|
1019
|
+
Tuple of (round_count_increment, new_consecutive_errors, should_break)
|
|
1020
|
+
"""
|
|
1021
|
+
try:
|
|
1022
|
+
logger.debug(f"Calling {processor.__class__.__name__}.process(round={self.current_round_number})")
|
|
1023
|
+
result = await processor.process(self.current_round_number)
|
|
1024
|
+
logger.debug(
|
|
1025
|
+
f"Processor returned: {result.__class__.__name__ if hasattr(result, '__class__') else type(result)}"
|
|
1026
|
+
)
|
|
1027
|
+
|
|
1028
|
+
# Check for state transition recommendations
|
|
1029
|
+
if current_state == AgentState.WORK:
|
|
1030
|
+
# Check for scheduled dream tasks
|
|
1031
|
+
if await self._check_scheduled_dream():
|
|
1032
|
+
logger.info("Scheduled dream time has arrived")
|
|
1033
|
+
await self._handle_state_transition(AgentState.DREAM)
|
|
1034
|
+
elif current_state == AgentState.SOLITUDE and processor == self.solitude_processor:
|
|
1035
|
+
# Check if the result indicates we should exit solitude
|
|
1036
|
+
if hasattr(result, "should_exit_solitude") and result.should_exit_solitude:
|
|
1037
|
+
exit_reason = getattr(result, "exit_reason", "Unknown reason")
|
|
1038
|
+
logger.info(f"Exiting solitude: {exit_reason}")
|
|
1039
|
+
await self._handle_state_transition(AgentState.WORK)
|
|
1040
|
+
|
|
1041
|
+
return 1, 0, False # increment round, reset errors, don't break
|
|
1042
|
+
|
|
1043
|
+
except Exception as e:
|
|
1044
|
+
consecutive_errors += 1
|
|
1045
|
+
logger.error(f"Error in {processor} for state {current_state}: {e}", exc_info=True)
|
|
1046
|
+
|
|
1047
|
+
if consecutive_errors >= max_consecutive_errors:
|
|
1048
|
+
logger.error(f"Too many consecutive processing errors ({consecutive_errors}), requesting shutdown")
|
|
1049
|
+
request_global_shutdown(f"Processing errors: {consecutive_errors} consecutive failures")
|
|
1050
|
+
return 0, consecutive_errors, True # don't increment round, keep errors, break
|
|
1051
|
+
|
|
1052
|
+
# Add backoff delay after errors
|
|
1053
|
+
await asyncio.sleep(min(consecutive_errors * 2, 30))
|
|
1054
|
+
return 0, consecutive_errors, False # don't increment round, keep errors, don't break
|
|
1055
|
+
|
|
1056
|
+
async def _process_dream_state(self) -> bool:
|
|
1057
|
+
"""
|
|
1058
|
+
Process dream state.
|
|
1059
|
+
|
|
1060
|
+
Returns:
|
|
1061
|
+
True to continue processing, False should not happen
|
|
1062
|
+
"""
|
|
1063
|
+
# Dream processing is handled by enhanced dream processor
|
|
1064
|
+
if not self.dream_processor._dream_task or self.dream_processor._dream_task.done():
|
|
1065
|
+
# Dream ended, transition back to WORK
|
|
1066
|
+
logger.info("Dream processing complete, returning to WORK state")
|
|
1067
|
+
await self._handle_state_transition(AgentState.WORK)
|
|
1068
|
+
else:
|
|
1069
|
+
await asyncio.sleep(5) # Check periodically
|
|
1070
|
+
return True
|
|
1071
|
+
|
|
1072
|
+
async def _process_shutdown_state(self, processor: Any, consecutive_errors: int) -> tuple[int, int, bool]:
|
|
1073
|
+
"""
|
|
1074
|
+
Process shutdown state with negotiation.
|
|
1075
|
+
|
|
1076
|
+
Args:
|
|
1077
|
+
processor: Shutdown processor
|
|
1078
|
+
consecutive_errors: Current consecutive error count
|
|
1079
|
+
|
|
1080
|
+
Returns:
|
|
1081
|
+
Tuple of (round_count_increment, new_consecutive_errors, should_break)
|
|
1082
|
+
"""
|
|
1083
|
+
logger.info("In SHUTDOWN state, processing shutdown negotiation")
|
|
1084
|
+
logger.debug(f"Shutdown processor from state_processors: {processor}")
|
|
1085
|
+
|
|
1086
|
+
if not processor:
|
|
1087
|
+
logger.error("No shutdown processor available")
|
|
1088
|
+
return 0, consecutive_errors, True
|
|
1089
|
+
|
|
1090
|
+
try:
|
|
1091
|
+
result = await processor.process(self.current_round_number)
|
|
1092
|
+
logger.info(f"Shutdown check - result type: {type(result)}, result: {result}")
|
|
1093
|
+
|
|
1094
|
+
# Handle ShutdownResult object (not dict)
|
|
1095
|
+
logger.debug(f"Result is object, checking for shutdown_ready: hasattr={hasattr(result, 'shutdown_ready')}")
|
|
1096
|
+
if hasattr(result, "shutdown_ready"):
|
|
1097
|
+
logger.debug(f"result.shutdown_ready = {result.shutdown_ready}")
|
|
1098
|
+
if result.shutdown_ready:
|
|
1099
|
+
logger.info("Shutdown negotiation complete (from result object), exiting processing loop")
|
|
1100
|
+
return 1, 0, True # increment round, reset errors, break
|
|
1101
|
+
|
|
1102
|
+
# Check processor's shutdown_complete attribute directly
|
|
1103
|
+
if hasattr(processor, "shutdown_complete"):
|
|
1104
|
+
logger.debug(f"processor.shutdown_complete = {processor.shutdown_complete}")
|
|
1105
|
+
if processor.shutdown_complete:
|
|
1106
|
+
logger.info(
|
|
1107
|
+
"Shutdown negotiation complete (processor.shutdown_complete is True), exiting processing loop"
|
|
1108
|
+
)
|
|
1109
|
+
return 1, 0, True # increment round, reset errors, break
|
|
1110
|
+
|
|
1111
|
+
return 1, 0, False # increment round, reset errors, don't break
|
|
1112
|
+
|
|
1113
|
+
except Exception as e:
|
|
1114
|
+
consecutive_errors += 1
|
|
1115
|
+
logger.error(f"Error in shutdown processor: {e}", exc_info=True)
|
|
1116
|
+
return 0, consecutive_errors, True # don't increment round, keep errors, break
|
|
1117
|
+
|
|
1118
|
+
def _calculate_round_delay(self, current_state: AgentState) -> float:
|
|
1119
|
+
"""
|
|
1120
|
+
Calculate delay between processing rounds based on config and state.
|
|
1121
|
+
|
|
1122
|
+
Args:
|
|
1123
|
+
current_state: Current agent state
|
|
1124
|
+
|
|
1125
|
+
Returns:
|
|
1126
|
+
Delay in seconds
|
|
1127
|
+
"""
|
|
1128
|
+
# Get delay from config, using mock LLM delay if enabled
|
|
1129
|
+
delay = 1.0
|
|
1130
|
+
if hasattr(self.app_config, "workflow"):
|
|
1131
|
+
mock_llm = getattr(self.app_config, "mock_llm", False)
|
|
1132
|
+
if hasattr(self.app_config.workflow, "get_round_delay"):
|
|
1133
|
+
delay = self.app_config.workflow.get_round_delay(mock_llm)
|
|
1134
|
+
elif hasattr(self.app_config.workflow, "round_delay_seconds"):
|
|
1135
|
+
delay = self.app_config.workflow.round_delay_seconds
|
|
1136
|
+
|
|
1137
|
+
# State-specific delays override config only if not using mock LLM
|
|
1138
|
+
if not getattr(self.app_config, "mock_llm", False):
|
|
1139
|
+
if current_state == AgentState.WORK:
|
|
1140
|
+
delay = 3.0 # 3 second delay in work mode as requested
|
|
1141
|
+
elif current_state == AgentState.SOLITUDE:
|
|
1142
|
+
delay = 10.0 # Slower pace in solitude
|
|
1143
|
+
elif current_state == AgentState.DREAM:
|
|
1144
|
+
delay = 5.0 # Check dream state periodically
|
|
1145
|
+
|
|
1146
|
+
return delay
|
|
1147
|
+
|
|
1148
|
+
async def _handle_delay_with_stop_check(self, delay: float) -> bool:
|
|
1149
|
+
"""
|
|
1150
|
+
Handle delay with stop event checking.
|
|
1151
|
+
|
|
1152
|
+
Args:
|
|
1153
|
+
delay: Delay time in seconds
|
|
1154
|
+
|
|
1155
|
+
Returns:
|
|
1156
|
+
True to continue processing, False to break from loop
|
|
1157
|
+
"""
|
|
1158
|
+
if delay > 0 and not (self._stop_event is not None and self._stop_event.is_set()):
|
|
1159
|
+
try:
|
|
1160
|
+
if self._stop_event is not None:
|
|
1161
|
+
await asyncio.wait_for(self._stop_event.wait(), timeout=delay)
|
|
1162
|
+
return False # Stop event was set
|
|
1163
|
+
else:
|
|
1164
|
+
await asyncio.sleep(delay)
|
|
1165
|
+
except asyncio.TimeoutError:
|
|
1166
|
+
pass # Continue processing
|
|
1167
|
+
return True
|
|
1168
|
+
|
|
1169
|
+
async def _process_single_round(
|
|
1170
|
+
self, round_count: int, consecutive_errors: int, max_consecutive_errors: int, num_rounds: Optional[int]
|
|
1171
|
+
) -> tuple[int, int, bool]:
|
|
1172
|
+
"""
|
|
1173
|
+
Process a single round of the main loop.
|
|
1174
|
+
|
|
1175
|
+
Returns:
|
|
1176
|
+
Tuple of (new_round_count, new_consecutive_errors, should_break)
|
|
1177
|
+
"""
|
|
1178
|
+
# Check if we've reached target rounds
|
|
1179
|
+
if self._should_stop_after_target_rounds(round_count, num_rounds):
|
|
1180
|
+
return round_count, consecutive_errors, True
|
|
1181
|
+
|
|
1182
|
+
# COVENANT COMPLIANCE: Check pause state before processing
|
|
1183
|
+
if not await self._check_pause_state():
|
|
1184
|
+
return round_count, consecutive_errors, False
|
|
1185
|
+
|
|
1186
|
+
# Update round number
|
|
1187
|
+
self.current_round_number += 1
|
|
1188
|
+
|
|
1189
|
+
# Handle shutdown transitions
|
|
1190
|
+
current_state = self.state_manager.get_state()
|
|
1191
|
+
if not await self._handle_shutdown_transitions(current_state):
|
|
1192
|
+
return round_count, consecutive_errors, True
|
|
1193
|
+
|
|
1194
|
+
# Process current state
|
|
1195
|
+
round_count, consecutive_errors, should_break = await self._process_current_state(
|
|
1196
|
+
round_count, consecutive_errors, max_consecutive_errors, current_state
|
|
1197
|
+
)
|
|
1198
|
+
if should_break:
|
|
1199
|
+
return round_count, consecutive_errors, True
|
|
1200
|
+
|
|
1201
|
+
# Handle delay between rounds
|
|
1202
|
+
if not await self._handle_round_delay(current_state):
|
|
1203
|
+
return round_count, consecutive_errors, True
|
|
1204
|
+
|
|
1205
|
+
return round_count, consecutive_errors, False
|
|
1206
|
+
|
|
1207
|
+
def _should_stop_after_target_rounds(self, round_count: int, num_rounds: Optional[int]) -> bool:
|
|
1208
|
+
"""Check if processing should stop after reaching target rounds."""
|
|
1209
|
+
if num_rounds is not None and round_count >= num_rounds:
|
|
1210
|
+
logger.info(f"Reached target rounds ({num_rounds}), requesting graceful shutdown")
|
|
1211
|
+
request_global_shutdown(f"Processing completed after {num_rounds} rounds")
|
|
1212
|
+
return True
|
|
1213
|
+
return False
|
|
1214
|
+
|
|
1215
|
+
async def _process_current_state(
|
|
1216
|
+
self, round_count: int, consecutive_errors: int, max_consecutive_errors: int, current_state: AgentState
|
|
1217
|
+
) -> tuple[int, int, bool]:
|
|
1218
|
+
"""Process based on the current agent state."""
|
|
1219
|
+
logger.debug(f"Processing round {round_count}, current state: {current_state}")
|
|
1220
|
+
|
|
1221
|
+
# Get processor for current state
|
|
1222
|
+
processor = self.state_processors.get(current_state)
|
|
1223
|
+
logger.debug(
|
|
1224
|
+
f"Got processor for state {current_state}: {processor.__class__.__name__ if processor else 'None'}"
|
|
1225
|
+
)
|
|
1226
|
+
|
|
1227
|
+
if processor and current_state != AgentState.SHUTDOWN:
|
|
1228
|
+
return await self._handle_regular_state_processing(
|
|
1229
|
+
processor, current_state, consecutive_errors, max_consecutive_errors, round_count
|
|
1230
|
+
)
|
|
1231
|
+
elif current_state == AgentState.DREAM:
|
|
1232
|
+
return await self._handle_dream_state_processing(round_count, consecutive_errors)
|
|
1233
|
+
elif current_state == AgentState.SHUTDOWN:
|
|
1234
|
+
return await self._handle_shutdown_state_processing(consecutive_errors, round_count)
|
|
1235
|
+
else:
|
|
1236
|
+
return await self._handle_unknown_state(round_count, consecutive_errors, current_state)
|
|
1237
|
+
|
|
1238
|
+
async def _handle_regular_state_processing(
|
|
1239
|
+
self,
|
|
1240
|
+
processor: Any,
|
|
1241
|
+
current_state: AgentState,
|
|
1242
|
+
consecutive_errors: int,
|
|
1243
|
+
max_consecutive_errors: int,
|
|
1244
|
+
round_count: int,
|
|
1245
|
+
) -> tuple[int, int, bool]:
|
|
1246
|
+
"""Handle processing for regular (non-special) states."""
|
|
1247
|
+
round_increment, consecutive_errors, should_break = await self._process_regular_state(
|
|
1248
|
+
processor, current_state, consecutive_errors, max_consecutive_errors
|
|
1249
|
+
)
|
|
1250
|
+
round_count += round_increment
|
|
1251
|
+
return round_count, consecutive_errors, should_break
|
|
1252
|
+
|
|
1253
|
+
async def _handle_dream_state_processing(self, round_count: int, consecutive_errors: int) -> tuple[int, int, bool]:
|
|
1254
|
+
"""Handle dream state processing."""
|
|
1255
|
+
if not await self._process_dream_state():
|
|
1256
|
+
return round_count, consecutive_errors, True
|
|
1257
|
+
return round_count, consecutive_errors, False
|
|
1258
|
+
|
|
1259
|
+
async def _handle_shutdown_state_processing(
|
|
1260
|
+
self, consecutive_errors: int, round_count: int
|
|
1261
|
+
) -> tuple[int, int, bool]:
|
|
1262
|
+
"""Handle shutdown state processing."""
|
|
1263
|
+
processor = self.state_processors.get(AgentState.SHUTDOWN)
|
|
1264
|
+
round_increment, consecutive_errors, should_break = await self._process_shutdown_state(
|
|
1265
|
+
processor, consecutive_errors
|
|
1266
|
+
)
|
|
1267
|
+
round_count += round_increment
|
|
1268
|
+
return round_count, consecutive_errors, should_break
|
|
1269
|
+
|
|
1270
|
+
async def _handle_unknown_state(
|
|
1271
|
+
self, round_count: int, consecutive_errors: int, current_state: AgentState
|
|
1272
|
+
) -> tuple[int, int, bool]:
|
|
1273
|
+
"""Handle unknown or unsupported states."""
|
|
1274
|
+
logger.warning(f"No processor for state: {current_state}")
|
|
1275
|
+
await asyncio.sleep(1)
|
|
1276
|
+
return round_count, consecutive_errors, False
|
|
1277
|
+
|
|
1278
|
+
async def _handle_round_delay(self, current_state: AgentState) -> bool:
|
|
1279
|
+
"""Handle delay between processing rounds."""
|
|
1280
|
+
delay = self._calculate_round_delay(current_state)
|
|
1281
|
+
return await self._handle_delay_with_stop_check(delay)
|
|
1282
|
+
|
|
1283
|
+
async def _processing_loop(self, num_rounds: Optional[int] = None) -> None:
|
|
1284
|
+
"""Main processing loop with state management and comprehensive exception handling."""
|
|
1285
|
+
logger.info(f"Processing loop started (num_rounds: {num_rounds})")
|
|
1286
|
+
round_count = 0
|
|
1287
|
+
consecutive_errors = 0
|
|
1288
|
+
max_consecutive_errors = 5
|
|
1289
|
+
|
|
1290
|
+
try:
|
|
1291
|
+
logger.info("Entering main processing while loop...")
|
|
1292
|
+
while not (self._stop_event is not None and self._stop_event.is_set()):
|
|
1293
|
+
try:
|
|
1294
|
+
round_count, consecutive_errors, should_break = await self._process_single_round(
|
|
1295
|
+
round_count, consecutive_errors, max_consecutive_errors, num_rounds
|
|
1296
|
+
)
|
|
1297
|
+
if should_break:
|
|
1298
|
+
break
|
|
1299
|
+
|
|
1300
|
+
except Exception as e:
|
|
1301
|
+
consecutive_errors += 1
|
|
1302
|
+
logger.error(
|
|
1303
|
+
f"CRITICAL: Unhandled error in processing loop round {self.current_round_number}: {e}",
|
|
1304
|
+
exc_info=True,
|
|
1305
|
+
)
|
|
1306
|
+
|
|
1307
|
+
if consecutive_errors >= max_consecutive_errors:
|
|
1308
|
+
logger.error(
|
|
1309
|
+
f"Processing loop has failed {consecutive_errors} consecutive times, requesting shutdown"
|
|
1310
|
+
)
|
|
1311
|
+
request_global_shutdown(
|
|
1312
|
+
f"Critical processing loop failure: {consecutive_errors} consecutive errors"
|
|
1313
|
+
)
|
|
1314
|
+
break
|
|
1315
|
+
|
|
1316
|
+
# Emergency backoff after critical errors
|
|
1317
|
+
await asyncio.sleep(min(consecutive_errors * 5, 60))
|
|
1318
|
+
|
|
1319
|
+
except Exception as e:
|
|
1320
|
+
logger.error(f"FATAL: Catastrophic error in processing loop: {e}", exc_info=True)
|
|
1321
|
+
request_global_shutdown(f"Catastrophic processing loop error: {e}")
|
|
1322
|
+
raise
|
|
1323
|
+
finally:
|
|
1324
|
+
logger.info("Processing loop finished")
|
|
1325
|
+
|
|
1326
|
+
async def _handle_state_transition(self, target_state: AgentState) -> None:
|
|
1327
|
+
"""Handle transitioning to a new state."""
|
|
1328
|
+
current_state = self.state_manager.get_state()
|
|
1329
|
+
|
|
1330
|
+
if not await self.state_manager.transition_to(target_state):
|
|
1331
|
+
logger.error(f"Failed to transition from {current_state} to {target_state}")
|
|
1332
|
+
return
|
|
1333
|
+
|
|
1334
|
+
if target_state == AgentState.SHUTDOWN:
|
|
1335
|
+
# Special handling for shutdown transition
|
|
1336
|
+
logger.info("Transitioning to SHUTDOWN - clearing non-shutdown thoughts from queue")
|
|
1337
|
+
# The shutdown processor will create its own thoughts
|
|
1338
|
+
# Any pending thoughts will be cleaned up on next startup
|
|
1339
|
+
|
|
1340
|
+
elif target_state == AgentState.DREAM:
|
|
1341
|
+
logger.info("Entering DREAM state for self-reflection")
|
|
1342
|
+
# Start the enhanced dream processor
|
|
1343
|
+
if self.dream_processor:
|
|
1344
|
+
await self.dream_processor.start_dreaming(duration=30 * 60) # 30 minutes default
|
|
1345
|
+
else:
|
|
1346
|
+
logger.error("Dream processor not available")
|
|
1347
|
+
|
|
1348
|
+
elif target_state == AgentState.WORK and current_state == AgentState.DREAM:
|
|
1349
|
+
if self.dream_processor:
|
|
1350
|
+
# Check if dream is already stopping (e.g., called from within _exit_phase)
|
|
1351
|
+
# to avoid deadlock when awaiting the dream task from within itself
|
|
1352
|
+
is_already_stopping = self.dream_processor._stop_event and self.dream_processor._stop_event.is_set()
|
|
1353
|
+
if not is_already_stopping:
|
|
1354
|
+
await self.dream_processor.stop_dreaming()
|
|
1355
|
+
summary = self.dream_processor.get_dream_summary()
|
|
1356
|
+
logger.info(f"Dream summary: {summary}")
|
|
1357
|
+
else:
|
|
1358
|
+
logger.info("Dream processor not available, no cleanup needed")
|
|
1359
|
+
|
|
1360
|
+
if target_state in self.state_processors:
|
|
1361
|
+
processor = self.state_processors[target_state]
|
|
1362
|
+
processor.initialize()
|
|
1363
|
+
|
|
1364
|
+
async def process(self, round_number: int) -> ProcessingRoundResult:
|
|
1365
|
+
"""Execute one round of processing based on current state."""
|
|
1366
|
+
current_state = self.state_manager.get_state()
|
|
1367
|
+
processor = self.state_processors.get(current_state)
|
|
1368
|
+
|
|
1369
|
+
if processor:
|
|
1370
|
+
# Return typed result directly from processor
|
|
1371
|
+
typed_result = await processor.process(round_number)
|
|
1372
|
+
|
|
1373
|
+
# Convert to ProcessingRoundResult if needed
|
|
1374
|
+
if isinstance(typed_result, ProcessingRoundResult):
|
|
1375
|
+
return typed_result
|
|
1376
|
+
elif hasattr(typed_result, "model_dump"):
|
|
1377
|
+
# Convert other result types to ProcessingRoundResult
|
|
1378
|
+
result_dict = typed_result.model_dump()
|
|
1379
|
+
return ProcessingRoundResult(
|
|
1380
|
+
round_number=round_number,
|
|
1381
|
+
state=current_state,
|
|
1382
|
+
processor_name=processor.__class__.__name__,
|
|
1383
|
+
success=result_dict.get("success", True),
|
|
1384
|
+
items_processed=result_dict.get("items_processed", 0),
|
|
1385
|
+
errors=result_dict.get("errors", 0),
|
|
1386
|
+
state_changed=False,
|
|
1387
|
+
new_state=None,
|
|
1388
|
+
processing_time_ms=result_dict.get("duration_seconds", 0) * 1000,
|
|
1389
|
+
details=result_dict,
|
|
1390
|
+
)
|
|
1391
|
+
else:
|
|
1392
|
+
# Fallback for untyped results
|
|
1393
|
+
return ProcessingRoundResult(
|
|
1394
|
+
round_number=round_number,
|
|
1395
|
+
state=current_state,
|
|
1396
|
+
processor_name=processor.__class__.__name__,
|
|
1397
|
+
success=True,
|
|
1398
|
+
items_processed=0,
|
|
1399
|
+
errors=0,
|
|
1400
|
+
state_changed=False,
|
|
1401
|
+
new_state=None,
|
|
1402
|
+
processing_time_ms=0.0,
|
|
1403
|
+
details={},
|
|
1404
|
+
)
|
|
1405
|
+
elif current_state == AgentState.DREAM:
|
|
1406
|
+
# Dream state handled separately
|
|
1407
|
+
return ProcessingRoundResult(
|
|
1408
|
+
round_number=round_number,
|
|
1409
|
+
state=current_state,
|
|
1410
|
+
processor_name="DreamProcessor",
|
|
1411
|
+
success=True,
|
|
1412
|
+
items_processed=0,
|
|
1413
|
+
errors=0,
|
|
1414
|
+
state_changed=False,
|
|
1415
|
+
new_state=None,
|
|
1416
|
+
processing_time_ms=0.0,
|
|
1417
|
+
details={"state": "dream"},
|
|
1418
|
+
)
|
|
1419
|
+
else:
|
|
1420
|
+
return ProcessingRoundResult(
|
|
1421
|
+
round_number=round_number,
|
|
1422
|
+
state=current_state,
|
|
1423
|
+
processor_name="Unknown",
|
|
1424
|
+
success=False,
|
|
1425
|
+
items_processed=0,
|
|
1426
|
+
errors=1,
|
|
1427
|
+
state_changed=False,
|
|
1428
|
+
new_state=None,
|
|
1429
|
+
processing_time_ms=0.0,
|
|
1430
|
+
details={"error": "No processor available"},
|
|
1431
|
+
)
|
|
1432
|
+
|
|
1433
|
+
def get_current_state(self) -> str:
|
|
1434
|
+
"""Get current processing state.
|
|
1435
|
+
|
|
1436
|
+
Returns:
|
|
1437
|
+
Current AgentState value as string
|
|
1438
|
+
"""
|
|
1439
|
+
return self.state_manager.get_state().value
|
|
1440
|
+
|
|
1441
|
+
def get_status(self) -> JSONDict:
|
|
1442
|
+
"""Get current processor status."""
|
|
1443
|
+
status: JSONDict = {
|
|
1444
|
+
"state": self.state_manager.get_state().value,
|
|
1445
|
+
"state_duration": self.state_manager.get_state_duration(),
|
|
1446
|
+
"round_number": self.current_round_number,
|
|
1447
|
+
"is_processing": self._processing_task is not None and not self._processing_task.done(),
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
current_state = self.state_manager.get_state()
|
|
1451
|
+
|
|
1452
|
+
if current_state == AgentState.WAKEUP:
|
|
1453
|
+
status["wakeup_status"] = self.wakeup_processor.get_status()
|
|
1454
|
+
|
|
1455
|
+
elif current_state == AgentState.WORK:
|
|
1456
|
+
status["work_status"] = self.work_processor.get_status()
|
|
1457
|
+
|
|
1458
|
+
elif current_state == AgentState.PLAY:
|
|
1459
|
+
status["play_status"] = self.play_processor.get_status()
|
|
1460
|
+
|
|
1461
|
+
elif current_state == AgentState.SOLITUDE:
|
|
1462
|
+
# Serialize solitude status to dict for JSONDict compatibility
|
|
1463
|
+
solitude_status = self.solitude_processor.get_status()
|
|
1464
|
+
if hasattr(solitude_status, "model_dump"):
|
|
1465
|
+
serialized_status = solitude_status.model_dump()
|
|
1466
|
+
elif isinstance(solitude_status, dict):
|
|
1467
|
+
serialized_status = dict(solitude_status)
|
|
1468
|
+
else:
|
|
1469
|
+
serialized_status = {"status": "unknown"}
|
|
1470
|
+
status["solitude_status"] = serialized_status
|
|
1471
|
+
|
|
1472
|
+
elif current_state == AgentState.DREAM:
|
|
1473
|
+
if self.dream_processor:
|
|
1474
|
+
status["dream_summary"] = self.dream_processor.get_dream_summary()
|
|
1475
|
+
else:
|
|
1476
|
+
status["dream_summary"] = {"state": "unavailable", "error": "Dream processor not available"}
|
|
1477
|
+
|
|
1478
|
+
# Initialize processor_metrics as a dict for JSONDict compatibility
|
|
1479
|
+
processor_metrics: JSONDict = {}
|
|
1480
|
+
for state, processor in self.state_processors.items():
|
|
1481
|
+
metrics = processor.get_metrics()
|
|
1482
|
+
# Serialize ProcessorMetrics to dict if it's a Pydantic model, ensuring JSONDict compatibility
|
|
1483
|
+
if hasattr(metrics, "model_dump"):
|
|
1484
|
+
serialized_metrics = metrics.model_dump()
|
|
1485
|
+
elif isinstance(metrics, dict):
|
|
1486
|
+
serialized_metrics = dict(metrics)
|
|
1487
|
+
else:
|
|
1488
|
+
serialized_metrics = {"error": "metrics unavailable"}
|
|
1489
|
+
processor_metrics[state.value] = serialized_metrics
|
|
1490
|
+
status["processor_metrics"] = processor_metrics
|
|
1491
|
+
|
|
1492
|
+
status["queue_status"] = self._get_detailed_queue_status()
|
|
1493
|
+
|
|
1494
|
+
return status
|
|
1495
|
+
|
|
1496
|
+
async def _schedule_initial_dream(self) -> None:
|
|
1497
|
+
"""Schedule the first dream session 6 hours from startup."""
|
|
1498
|
+
try:
|
|
1499
|
+
from ciris_engine.schemas.services.graph_core import GraphNode, GraphScope, NodeType
|
|
1500
|
+
|
|
1501
|
+
memory_service = self._get_service("memory_service")
|
|
1502
|
+
if not memory_service:
|
|
1503
|
+
logger.warning("Cannot schedule initial dream - no memory service")
|
|
1504
|
+
return
|
|
1505
|
+
|
|
1506
|
+
# Schedule 6 hours from now
|
|
1507
|
+
dream_time = self._time_service.now() + timedelta(hours=6)
|
|
1508
|
+
|
|
1509
|
+
dream_task = GraphNode(
|
|
1510
|
+
id=f"dream_schedule_{int(dream_time.timestamp())}",
|
|
1511
|
+
type=NodeType.CONCEPT,
|
|
1512
|
+
scope=GraphScope.LOCAL,
|
|
1513
|
+
attributes={
|
|
1514
|
+
"task_type": "scheduled_dream",
|
|
1515
|
+
"scheduled_for": dream_time.isoformat(),
|
|
1516
|
+
"duration_minutes": 30,
|
|
1517
|
+
"priority": "health_maintenance",
|
|
1518
|
+
"can_defer": True,
|
|
1519
|
+
"defer_window_hours": 2,
|
|
1520
|
+
"message": "Time for introspection and learning",
|
|
1521
|
+
"is_initial": True,
|
|
1522
|
+
},
|
|
1523
|
+
# Add missing required fields
|
|
1524
|
+
updated_by="main_processor",
|
|
1525
|
+
updated_at=self._time_service.now(),
|
|
1526
|
+
)
|
|
1527
|
+
|
|
1528
|
+
await memory_service.memorize(dream_task)
|
|
1529
|
+
|
|
1530
|
+
logger.info(f"Scheduled initial dream session for {dream_time.isoformat()}")
|
|
1531
|
+
|
|
1532
|
+
except Exception as e:
|
|
1533
|
+
logger.error(f"Failed to schedule initial dream: {e}")
|
|
1534
|
+
|
|
1535
|
+
async def _check_scheduled_dream(self) -> bool:
|
|
1536
|
+
"""Check if there's a scheduled dream task that's due."""
|
|
1537
|
+
try:
|
|
1538
|
+
# Import at function level to avoid circular imports
|
|
1539
|
+
from ciris_engine.schemas.services.graph_core import GraphScope
|
|
1540
|
+
from ciris_engine.schemas.services.operations import MemoryQuery
|
|
1541
|
+
|
|
1542
|
+
memory_service = self._get_service("memory_service")
|
|
1543
|
+
if not memory_service:
|
|
1544
|
+
return False
|
|
1545
|
+
|
|
1546
|
+
# Query for scheduled dream tasks
|
|
1547
|
+
query = MemoryQuery(
|
|
1548
|
+
node_id="dream_schedule_*", scope=GraphScope.LOCAL, type=None, include_edges=False, depth=1
|
|
1549
|
+
)
|
|
1550
|
+
|
|
1551
|
+
dream_tasks = await memory_service.recall(query)
|
|
1552
|
+
|
|
1553
|
+
now = self._time_service.now()
|
|
1554
|
+
|
|
1555
|
+
for task in dream_tasks:
|
|
1556
|
+
# Handle both dict and GraphNodeAttributes
|
|
1557
|
+
attributes = task.attributes
|
|
1558
|
+
scheduled_for = (
|
|
1559
|
+
attributes.get("scheduled_for")
|
|
1560
|
+
if hasattr(attributes, "get")
|
|
1561
|
+
else getattr(attributes, "scheduled_for", None)
|
|
1562
|
+
)
|
|
1563
|
+
if scheduled_for:
|
|
1564
|
+
# Parse ISO format datetime
|
|
1565
|
+
if isinstance(scheduled_for, str):
|
|
1566
|
+
# Handle both 'Z' and '+00:00' formats
|
|
1567
|
+
scheduled_str = scheduled_for
|
|
1568
|
+
if scheduled_str.endswith("Z"):
|
|
1569
|
+
scheduled_str = scheduled_str[:-1] + "+00:00"
|
|
1570
|
+
scheduled_time = datetime.fromisoformat(scheduled_str)
|
|
1571
|
+
else:
|
|
1572
|
+
scheduled_time = scheduled_for
|
|
1573
|
+
|
|
1574
|
+
# Check if it's time (with 2 hour defer window)
|
|
1575
|
+
# Handle both dict and GraphNodeAttributes
|
|
1576
|
+
attributes = task.attributes
|
|
1577
|
+
defer_hours = (
|
|
1578
|
+
attributes.get("defer_window_hours", 2)
|
|
1579
|
+
if hasattr(attributes, "get")
|
|
1580
|
+
else getattr(attributes, "defer_window_hours", 2)
|
|
1581
|
+
)
|
|
1582
|
+
defer_window = timedelta(hours=defer_hours)
|
|
1583
|
+
|
|
1584
|
+
if now >= scheduled_time and now <= scheduled_time + defer_window:
|
|
1585
|
+
# Check dream health - when was last dream?
|
|
1586
|
+
if self.dream_processor and self.dream_processor.dream_metrics.get("end_time"):
|
|
1587
|
+
from ciris_engine.logic.utils.jsondict_helpers import get_str
|
|
1588
|
+
|
|
1589
|
+
end_time_str = get_str(self.dream_processor.dream_metrics, "end_time", "")
|
|
1590
|
+
if end_time_str:
|
|
1591
|
+
last_dream = datetime.fromisoformat(end_time_str)
|
|
1592
|
+
else:
|
|
1593
|
+
# No valid end time, skip this check
|
|
1594
|
+
logger.debug("No valid dream end_time, allowing scheduled dream")
|
|
1595
|
+
logger.info(f"Scheduled dream task {task.id} is due")
|
|
1596
|
+
return True
|
|
1597
|
+
hours_since = (now - last_dream).total_seconds() / 3600
|
|
1598
|
+
|
|
1599
|
+
# Don't dream if we dreamed less than 4 hours ago
|
|
1600
|
+
if hours_since < 4:
|
|
1601
|
+
logger.debug(f"Skipping scheduled dream - last dream was {hours_since:.1f} hours ago")
|
|
1602
|
+
return False
|
|
1603
|
+
|
|
1604
|
+
logger.info(f"Scheduled dream task {task.id} is due")
|
|
1605
|
+
return True
|
|
1606
|
+
|
|
1607
|
+
return False
|
|
1608
|
+
|
|
1609
|
+
except Exception as e:
|
|
1610
|
+
logger.error(f"Error checking scheduled dreams: {e}")
|
|
1611
|
+
return False
|
|
1612
|
+
|
|
1613
|
+
def _get_detailed_queue_status(self) -> JSONDict:
|
|
1614
|
+
"""Get detailed processing queue status information."""
|
|
1615
|
+
try:
|
|
1616
|
+
# Get thought counts by status
|
|
1617
|
+
from ciris_engine.logic import persistence
|
|
1618
|
+
from ciris_engine.schemas.runtime.enums import ThoughtStatus
|
|
1619
|
+
|
|
1620
|
+
pending_count = persistence.count_thoughts_by_status(ThoughtStatus.PENDING, self.agent_occurrence_id)
|
|
1621
|
+
processing_count = persistence.count_thoughts_by_status(ThoughtStatus.PROCESSING, self.agent_occurrence_id)
|
|
1622
|
+
completed_count = persistence.count_thoughts_by_status(ThoughtStatus.COMPLETED, self.agent_occurrence_id)
|
|
1623
|
+
failed_count = persistence.count_thoughts_by_status(ThoughtStatus.FAILED, self.agent_occurrence_id)
|
|
1624
|
+
|
|
1625
|
+
# Get recent thought activity
|
|
1626
|
+
recent_thoughts = []
|
|
1627
|
+
try:
|
|
1628
|
+
# Get last 5 thoughts for activity overview
|
|
1629
|
+
from ciris_engine.logic.persistence.models.thoughts import get_recent_thoughts
|
|
1630
|
+
|
|
1631
|
+
recent_data = get_recent_thoughts(limit=5, occurrence_id=self.agent_occurrence_id)
|
|
1632
|
+
for thought_data in recent_data:
|
|
1633
|
+
content_str = str(thought_data.content or "")
|
|
1634
|
+
recent_thoughts.append(
|
|
1635
|
+
{
|
|
1636
|
+
"thought_id": thought_data.thought_id,
|
|
1637
|
+
"thought_type": thought_data.thought_type or "unknown",
|
|
1638
|
+
"status": thought_data.status or "unknown",
|
|
1639
|
+
"created_at": getattr(thought_data, "created_at", "unknown"),
|
|
1640
|
+
"content_preview": content_str[:100] + "..." if len(content_str) > 100 else content_str,
|
|
1641
|
+
}
|
|
1642
|
+
)
|
|
1643
|
+
except Exception as e:
|
|
1644
|
+
logger.warning(f"Could not fetch recent thoughts: {e}")
|
|
1645
|
+
recent_thoughts = []
|
|
1646
|
+
|
|
1647
|
+
# Get task information
|
|
1648
|
+
task_info: JSONDict = {}
|
|
1649
|
+
try:
|
|
1650
|
+
if hasattr(self, "work_processor") and self.work_processor:
|
|
1651
|
+
task_info = {
|
|
1652
|
+
"active_tasks": self.work_processor.task_manager.get_active_task_count(),
|
|
1653
|
+
"pending_tasks": self.work_processor.task_manager.get_pending_task_count(),
|
|
1654
|
+
}
|
|
1655
|
+
except Exception as e:
|
|
1656
|
+
logger.warning(f"Could not fetch task info: {e}")
|
|
1657
|
+
task_info = {"error": str(e)}
|
|
1658
|
+
|
|
1659
|
+
return {
|
|
1660
|
+
"thought_counts": {
|
|
1661
|
+
"pending": pending_count,
|
|
1662
|
+
"processing": processing_count,
|
|
1663
|
+
"completed": completed_count,
|
|
1664
|
+
"failed": failed_count,
|
|
1665
|
+
"total": pending_count + processing_count + completed_count + failed_count,
|
|
1666
|
+
},
|
|
1667
|
+
"recent_activity": recent_thoughts,
|
|
1668
|
+
"task_summary": task_info,
|
|
1669
|
+
"queue_health": {
|
|
1670
|
+
"has_pending_work": pending_count > 0,
|
|
1671
|
+
"has_processing_work": processing_count > 0,
|
|
1672
|
+
"has_recent_failures": failed_count > 0,
|
|
1673
|
+
"queue_utilization": (
|
|
1674
|
+
"high"
|
|
1675
|
+
if pending_count + processing_count > 10
|
|
1676
|
+
else "medium" if pending_count + processing_count > 3 else "low"
|
|
1677
|
+
),
|
|
1678
|
+
},
|
|
1679
|
+
}
|
|
1680
|
+
except Exception as e:
|
|
1681
|
+
logger.error(f"Error getting detailed queue status: {e}", exc_info=True)
|
|
1682
|
+
return {
|
|
1683
|
+
"error": str(e),
|
|
1684
|
+
"thought_counts": {"error": "Could not fetch counts"},
|
|
1685
|
+
"recent_activity": [],
|
|
1686
|
+
"task_summary": {"error": "Could not fetch task info"},
|
|
1687
|
+
"queue_health": {"error": "Could not determine health"},
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
def get_state_history(self, limit: int = 10) -> List[StateTransitionRecord]:
|
|
1691
|
+
"""
|
|
1692
|
+
Get recent state transition history.
|
|
1693
|
+
|
|
1694
|
+
Args:
|
|
1695
|
+
limit: Maximum number of transitions to return
|
|
1696
|
+
|
|
1697
|
+
Returns:
|
|
1698
|
+
List of state transitions with timestamps and reasons
|
|
1699
|
+
"""
|
|
1700
|
+
all_transitions = self.state_manager.get_state_history()
|
|
1701
|
+
# Return the most recent transitions up to the limit
|
|
1702
|
+
return all_transitions[-limit:] if len(all_transitions) > limit else all_transitions
|
|
1703
|
+
|
|
1704
|
+
def get_queue_status(self) -> Any:
|
|
1705
|
+
"""
|
|
1706
|
+
Get current queue status with pending tasks and thoughts.
|
|
1707
|
+
|
|
1708
|
+
Returns an object with pending_tasks and pending_thoughts attributes
|
|
1709
|
+
for use by the runtime control service.
|
|
1710
|
+
"""
|
|
1711
|
+
# Use the centralized persistence function
|
|
1712
|
+
return persistence.get_queue_status()
|
|
1713
|
+
|
|
1714
|
+
def _collect_metrics(self) -> JSONDict:
|
|
1715
|
+
"""Collect base metrics for the agent processor."""
|
|
1716
|
+
# Calculate uptime - MUST have start time
|
|
1717
|
+
if not hasattr(self, "_start_time") or not self._start_time:
|
|
1718
|
+
raise RuntimeError("Processor start time not tracked - cannot calculate uptime")
|
|
1719
|
+
|
|
1720
|
+
uptime_seconds = (datetime.now() - self._start_time).total_seconds()
|
|
1721
|
+
|
|
1722
|
+
# Get queue size from processing_queue if it exists
|
|
1723
|
+
queue_size = 0
|
|
1724
|
+
if hasattr(self, "processing_queue") and self.processing_queue:
|
|
1725
|
+
queue_size = self.processing_queue.size()
|
|
1726
|
+
|
|
1727
|
+
# Get current state
|
|
1728
|
+
current_state = self.state_manager.get_state() if hasattr(self, "state_manager") else None
|
|
1729
|
+
|
|
1730
|
+
# Basic metrics - explicitly type as JSONDict
|
|
1731
|
+
metrics: JSONDict = {
|
|
1732
|
+
"processor_uptime_seconds": uptime_seconds,
|
|
1733
|
+
"processor_queue_size": queue_size,
|
|
1734
|
+
"processor_healthy": True, # If we're collecting metrics, we're healthy
|
|
1735
|
+
"healthy": True, # For telemetry service compatibility
|
|
1736
|
+
"uptime_seconds": uptime_seconds, # For telemetry service compatibility
|
|
1737
|
+
"processor_current_state_name": current_state.value if current_state else "unknown",
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
return metrics
|
|
1741
|
+
|
|
1742
|
+
def get_metrics(self) -> JSONDict:
|
|
1743
|
+
"""Get all metrics including base, custom, and v1.4.3 specific."""
|
|
1744
|
+
# Get all base + custom metrics
|
|
1745
|
+
metrics = self._collect_metrics()
|
|
1746
|
+
|
|
1747
|
+
# Add v1.4.3 specific metrics
|
|
1748
|
+
# Calculate total thoughts processed by aggregating from all state processors
|
|
1749
|
+
total_thoughts = 0
|
|
1750
|
+
total_actions = 0
|
|
1751
|
+
|
|
1752
|
+
for processor in self.state_processors.values():
|
|
1753
|
+
if hasattr(processor, "metrics"):
|
|
1754
|
+
processor_metrics = processor.get_metrics()
|
|
1755
|
+
total_thoughts += processor_metrics.items_processed
|
|
1756
|
+
total_actions += processor_metrics.additional_metrics.actions_dispatched
|
|
1757
|
+
|
|
1758
|
+
# Get state transitions count from state manager history
|
|
1759
|
+
state_transitions = len(self.state_manager.get_state_history())
|
|
1760
|
+
|
|
1761
|
+
# Get current state as integer (AgentState enum values map to ints)
|
|
1762
|
+
current_state_int = self.state_manager.get_state().value
|
|
1763
|
+
|
|
1764
|
+
# Convert state string to integer mapping for the API
|
|
1765
|
+
state_mapping = {"wakeup": 0, "work": 1, "play": 2, "solitude": 3, "dream": 4, "shutdown": 5}
|
|
1766
|
+
current_state_value = state_mapping.get(current_state_int.lower(), 0)
|
|
1767
|
+
|
|
1768
|
+
metrics.update(
|
|
1769
|
+
{
|
|
1770
|
+
"processor_thoughts_total": total_thoughts,
|
|
1771
|
+
"processor_actions_total": total_actions,
|
|
1772
|
+
"processor_state_transitions": state_transitions,
|
|
1773
|
+
"processor_current_state": current_state_value,
|
|
1774
|
+
}
|
|
1775
|
+
)
|
|
1776
|
+
|
|
1777
|
+
return metrics
|