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.
Files changed (986) hide show
  1. ciris_adapters/README.md +113 -0
  2. ciris_adapters/__init__.py +30 -0
  3. ciris_adapters/ciris_covenant_metrics/README.md +144 -0
  4. ciris_adapters/ciris_covenant_metrics/__init__.py +36 -0
  5. ciris_adapters/ciris_covenant_metrics/adapter.py +249 -0
  6. ciris_adapters/ciris_covenant_metrics/manifest.json +152 -0
  7. ciris_adapters/ciris_covenant_metrics/services.py +403 -0
  8. ciris_adapters/ciris_hosted_tools/__init__.py +24 -0
  9. ciris_adapters/ciris_hosted_tools/adapter.py +169 -0
  10. ciris_adapters/ciris_hosted_tools/manifest.json +94 -0
  11. ciris_adapters/ciris_hosted_tools/services.py +744 -0
  12. ciris_adapters/external_data_sql/README.md +559 -0
  13. ciris_adapters/external_data_sql/__init__.py +43 -0
  14. ciris_adapters/external_data_sql/adapter.py +144 -0
  15. ciris_adapters/external_data_sql/configurable.py +315 -0
  16. ciris_adapters/external_data_sql/dialects/__init__.py +37 -0
  17. ciris_adapters/external_data_sql/dialects/base.py +133 -0
  18. ciris_adapters/external_data_sql/dialects/mysql.py +63 -0
  19. ciris_adapters/external_data_sql/dialects/postgresql.py +59 -0
  20. ciris_adapters/external_data_sql/dialects/sqlite.py +62 -0
  21. ciris_adapters/external_data_sql/example_config.json +88 -0
  22. ciris_adapters/external_data_sql/example_privacy_schema.yaml +127 -0
  23. ciris_adapters/external_data_sql/manifest.json +195 -0
  24. ciris_adapters/external_data_sql/privacy_schema_loader.py +189 -0
  25. ciris_adapters/external_data_sql/protocol.py +101 -0
  26. ciris_adapters/external_data_sql/schemas.py +146 -0
  27. ciris_adapters/external_data_sql/service.py +1547 -0
  28. ciris_adapters/external_data_sql/service_old.py +492 -0
  29. ciris_adapters/home_assistant/__init__.py +63 -0
  30. ciris_adapters/home_assistant/adapter.py +201 -0
  31. ciris_adapters/home_assistant/communication_service.py +347 -0
  32. ciris_adapters/home_assistant/configurable.py +667 -0
  33. ciris_adapters/home_assistant/manifest.json +203 -0
  34. ciris_adapters/home_assistant/schemas.py +129 -0
  35. ciris_adapters/home_assistant/service.py +751 -0
  36. ciris_adapters/home_assistant/tool_service.py +441 -0
  37. ciris_adapters/mcp_client/__init__.py +82 -0
  38. ciris_adapters/mcp_client/adapter.py +847 -0
  39. ciris_adapters/mcp_client/config.py +280 -0
  40. ciris_adapters/mcp_client/configurable.py +422 -0
  41. ciris_adapters/mcp_client/manifest.json +185 -0
  42. ciris_adapters/mcp_client/mcp_communication_service.py +393 -0
  43. ciris_adapters/mcp_client/mcp_tool_service.py +463 -0
  44. ciris_adapters/mcp_client/mcp_wise_service.py +394 -0
  45. ciris_adapters/mcp_client/schemas.py +149 -0
  46. ciris_adapters/mcp_client/security.py +592 -0
  47. ciris_adapters/mcp_common/__init__.py +44 -0
  48. ciris_adapters/mcp_common/manifest.json +25 -0
  49. ciris_adapters/mcp_common/protocol.py +315 -0
  50. ciris_adapters/mcp_common/schemas.py +225 -0
  51. ciris_adapters/mcp_server/__init__.py +47 -0
  52. ciris_adapters/mcp_server/adapter.py +581 -0
  53. ciris_adapters/mcp_server/config.py +260 -0
  54. ciris_adapters/mcp_server/configurable.py +393 -0
  55. ciris_adapters/mcp_server/handlers.py +663 -0
  56. ciris_adapters/mcp_server/manifest.json +211 -0
  57. ciris_adapters/mcp_server/security.py +500 -0
  58. ciris_adapters/mock_llm/README.md +117 -0
  59. ciris_adapters/mock_llm/__init__.py +21 -0
  60. ciris_adapters/mock_llm/adapter.py +131 -0
  61. ciris_adapters/mock_llm/configurable.py +237 -0
  62. ciris_adapters/mock_llm/manifest.json +106 -0
  63. ciris_adapters/mock_llm/protocol.py +37 -0
  64. ciris_adapters/mock_llm/responses.py +520 -0
  65. ciris_adapters/mock_llm/responses_action_selection.py +1041 -0
  66. ciris_adapters/mock_llm/responses_epistemic.py +17 -0
  67. ciris_adapters/mock_llm/responses_feedback.py +27 -0
  68. ciris_adapters/mock_llm/schemas.py +35 -0
  69. ciris_adapters/mock_llm/service.py +294 -0
  70. ciris_adapters/navigation/__init__.py +21 -0
  71. ciris_adapters/navigation/adapter.py +129 -0
  72. ciris_adapters/navigation/configurable.py +239 -0
  73. ciris_adapters/navigation/manifest.json +104 -0
  74. ciris_adapters/navigation/service.py +487 -0
  75. ciris_adapters/reddit/README.md +132 -0
  76. ciris_adapters/reddit/REDDIT_ADAPTER_ANALYSIS.md +715 -0
  77. ciris_adapters/reddit/REDDIT_ADAPTER_SUMMARY.txt +278 -0
  78. ciris_adapters/reddit/REDDIT_ANALYSIS_INDEX.md +307 -0
  79. ciris_adapters/reddit/REDDIT_PRODUCTION_READINESS_PLAN.md +518 -0
  80. ciris_adapters/reddit/__init__.py +15 -0
  81. ciris_adapters/reddit/adapter.py +189 -0
  82. ciris_adapters/reddit/configurable.py +274 -0
  83. ciris_adapters/reddit/error_handler.py +307 -0
  84. ciris_adapters/reddit/manifest.json +218 -0
  85. ciris_adapters/reddit/observer.py +532 -0
  86. ciris_adapters/reddit/protocol.py +34 -0
  87. ciris_adapters/reddit/schemas.py +433 -0
  88. ciris_adapters/reddit/service.py +1471 -0
  89. ciris_adapters/sample_adapter/README.md +474 -0
  90. ciris_adapters/sample_adapter/__init__.py +45 -0
  91. ciris_adapters/sample_adapter/adapter.py +208 -0
  92. ciris_adapters/sample_adapter/configurable.py +469 -0
  93. ciris_adapters/sample_adapter/manifest.json +247 -0
  94. ciris_adapters/sample_adapter/services.py +486 -0
  95. ciris_adapters/weather/__init__.py +16 -0
  96. ciris_adapters/weather/adapter.py +130 -0
  97. ciris_adapters/weather/configurable.py +240 -0
  98. ciris_adapters/weather/manifest.json +156 -0
  99. ciris_adapters/weather/service.py +600 -0
  100. ciris_agent-1.7.7.dist-info/METADATA +284 -0
  101. ciris_agent-1.7.7.dist-info/RECORD +986 -0
  102. ciris_agent-1.7.7.dist-info/WHEEL +5 -0
  103. ciris_agent-1.7.7.dist-info/entry_points.txt +15 -0
  104. ciris_agent-1.7.7.dist-info/licenses/LICENSE +205 -0
  105. ciris_agent-1.7.7.dist-info/licenses/NOTICE +82 -0
  106. ciris_agent-1.7.7.dist-info/top_level.txt +4 -0
  107. ciris_engine/__init__.py +15 -0
  108. ciris_engine/ciris_templates/ally.yaml +632 -0
  109. ciris_engine/ciris_templates/default.yaml +411 -0
  110. ciris_engine/ciris_templates/echo-core.yaml +629 -0
  111. ciris_engine/ciris_templates/echo-speculative.yaml +764 -0
  112. ciris_engine/ciris_templates/echo.yaml +647 -0
  113. ciris_engine/ciris_templates/sage.yaml +332 -0
  114. ciris_engine/ciris_templates/scout.yaml +338 -0
  115. ciris_engine/ciris_templates/test.yaml +168 -0
  116. ciris_engine/cli.py +42 -0
  117. ciris_engine/config/CIRIS_SERVICES.json +19 -0
  118. ciris_engine/config/MODEL_CAPABILITIES.json +419 -0
  119. ciris_engine/config/PRICING_DATA.json +179 -0
  120. ciris_engine/config/__init__.py +50 -0
  121. ciris_engine/config/ciris_services.py +113 -0
  122. ciris_engine/config/model_capabilities.py +388 -0
  123. ciris_engine/config/pricing_models.py +276 -0
  124. ciris_engine/constants.py +35 -0
  125. ciris_engine/data/__init__.py +1 -0
  126. ciris_engine/data/covenant_1.0b.txt +978 -0
  127. ciris_engine/gui_static/11steps.svg +107 -0
  128. ciris_engine/gui_static/2x-schematics.png +0 -0
  129. ciris_engine/gui_static/404/index.html +1 -0
  130. ciris_engine/gui_static/404.html +1 -0
  131. ciris_engine/gui_static/_next/static/0edhkwDxd5UccTsCmtaBi/_buildManifest.js +1 -0
  132. ciris_engine/gui_static/_next/static/0edhkwDxd5UccTsCmtaBi/_ssgManifest.js +1 -0
  133. ciris_engine/gui_static/_next/static/U-3xTQao7hc2wnAi-Uekm/_buildManifest.js +1 -0
  134. ciris_engine/gui_static/_next/static/U-3xTQao7hc2wnAi-Uekm/_ssgManifest.js +1 -0
  135. ciris_engine/gui_static/_next/static/chunks/3297-60e86ba0f8a7b040.js +1 -0
  136. ciris_engine/gui_static/_next/static/chunks/3835-2aad4b7f5f8e4643.js +1 -0
  137. ciris_engine/gui_static/_next/static/chunks/4499-99a0bc47de0b8975.js +1 -0
  138. ciris_engine/gui_static/_next/static/chunks/4534-af88cd4ba6e99bff.js +1 -0
  139. ciris_engine/gui_static/_next/static/chunks/4541-84b455f9e0dc4cfe.js +1 -0
  140. ciris_engine/gui_static/_next/static/chunks/4789-61412711484754bb.js +1 -0
  141. ciris_engine/gui_static/_next/static/chunks/6539-c6398bc9d7018430.js +1 -0
  142. ciris_engine/gui_static/_next/static/chunks/704-8e827b26cc8c2d32.js +1 -0
  143. ciris_engine/gui_static/_next/static/chunks/704-fb45d630f3192c6f.js +1 -0
  144. ciris_engine/gui_static/_next/static/chunks/8072-de4952a2e6d2b33f.js +1 -0
  145. ciris_engine/gui_static/_next/static/chunks/8315-b91d03a3949db0af.js +1 -0
  146. ciris_engine/gui_static/_next/static/chunks/8386-f93a83ccbd789bd9.js +1 -0
  147. ciris_engine/gui_static/_next/static/chunks/87c73c54-781a7f35148d5433.js +1 -0
  148. ciris_engine/gui_static/_next/static/chunks/8903-fefea3339a02d41b.js +1 -0
  149. ciris_engine/gui_static/_next/static/chunks/9090-e66485adf8d9d990.js +1 -0
  150. ciris_engine/gui_static/_next/static/chunks/app/_not-found/page-a67d9808462c23b1.js +1 -0
  151. ciris_engine/gui_static/_next/static/chunks/app/account/api-keys/page-2d7ee1583bbbd02e.js +1 -0
  152. ciris_engine/gui_static/_next/static/chunks/app/account/api-keys/page-6a3c2bae6fe92b7b.js +1 -0
  153. ciris_engine/gui_static/_next/static/chunks/app/account/consent/page-2ed3a035136bc4e8.js +1 -0
  154. ciris_engine/gui_static/_next/static/chunks/app/account/consent/page-b2f5c91844a32422.js +1 -0
  155. ciris_engine/gui_static/_next/static/chunks/app/account/page-25b90f89af3ea58c.js +1 -0
  156. ciris_engine/gui_static/_next/static/chunks/app/account/page-b65d16c94ecaf69c.js +1 -0
  157. ciris_engine/gui_static/_next/static/chunks/app/account/privacy/page-675b6d05c8f9184f.js +1 -0
  158. ciris_engine/gui_static/_next/static/chunks/app/account/privacy/page-cbee2e1c8ab52145.js +1 -0
  159. ciris_engine/gui_static/_next/static/chunks/app/account/settings/page-0f44da06697cf9f0.js +1 -0
  160. ciris_engine/gui_static/_next/static/chunks/app/account/settings/page-563420253577edbf.js +1 -0
  161. ciris_engine/gui_static/_next/static/chunks/app/adapters/page-1854631018bc32be.js +1 -0
  162. ciris_engine/gui_static/_next/static/chunks/app/agents/page-8353752c176a7c70.js +1 -0
  163. ciris_engine/gui_static/_next/static/chunks/app/agents/page-f61a529f110a6040.js +1 -0
  164. ciris_engine/gui_static/_next/static/chunks/app/api-demo/page-7f19b9d20d39be28.js +1 -0
  165. ciris_engine/gui_static/_next/static/chunks/app/api-demo/page-d1063938f249b8bd.js +1 -0
  166. ciris_engine/gui_static/_next/static/chunks/app/audit/page-321b6728b8fff0bb.js +1 -0
  167. ciris_engine/gui_static/_next/static/chunks/app/audit/page-ebac35ca961a1277.js +1 -0
  168. ciris_engine/gui_static/_next/static/chunks/app/billing/page-6f3dc3bd02924f8e.js +1 -0
  169. ciris_engine/gui_static/_next/static/chunks/app/billing/page-fa4a469f814c821a.js +1 -0
  170. ciris_engine/gui_static/_next/static/chunks/app/comms/page-0d4f734269addd8f.js +1 -0
  171. ciris_engine/gui_static/_next/static/chunks/app/comms/page-79227d426050089c.js +1 -0
  172. ciris_engine/gui_static/_next/static/chunks/app/config/page-018d21d683b6e5bc.js +1 -0
  173. ciris_engine/gui_static/_next/static/chunks/app/config/page-2aa5a5363ca2a371.js +1 -0
  174. ciris_engine/gui_static/_next/static/chunks/app/consent/page-198373205fd316e2.js +1 -0
  175. ciris_engine/gui_static/_next/static/chunks/app/consent/page-f2ca39e7713b13f8.js +1 -0
  176. ciris_engine/gui_static/_next/static/chunks/app/dashboard/page-1dd5a196f643c60d.js +1 -0
  177. ciris_engine/gui_static/_next/static/chunks/app/dashboard/page-530a04d3abbb8cda.js +1 -0
  178. ciris_engine/gui_static/_next/static/chunks/app/docs/page-3193b06d094ab654.js +1 -0
  179. ciris_engine/gui_static/_next/static/chunks/app/docs/page-330e996dedb87aba.js +1 -0
  180. ciris_engine/gui_static/_next/static/chunks/app/layout-0a70f5fc460298b1.js +1 -0
  181. ciris_engine/gui_static/_next/static/chunks/app/layout-21f2f99dd5b336e9.js +1 -0
  182. ciris_engine/gui_static/_next/static/chunks/app/login/page-33240e6c6034a49d.js +1 -0
  183. ciris_engine/gui_static/_next/static/chunks/app/login/page-68ffab6d54a7fdcd.js +1 -0
  184. ciris_engine/gui_static/_next/static/chunks/app/logs/page-8a6167aecc4a475c.js +1 -0
  185. ciris_engine/gui_static/_next/static/chunks/app/memory/page-9ca8c5d0056de3ff.js +1 -0
  186. ciris_engine/gui_static/_next/static/chunks/app/memory/page-e961226941c18f81.js +1 -0
  187. ciris_engine/gui_static/_next/static/chunks/app/page-6fdb065a787a4974.js +1 -0
  188. ciris_engine/gui_static/_next/static/chunks/app/page-89f87d431be6064a.js +1 -0
  189. ciris_engine/gui_static/_next/static/chunks/app/runtime/page-2e728b9c43aa164d.js +1 -0
  190. ciris_engine/gui_static/_next/static/chunks/app/runtime/page-c7dd033dc40a72f0.js +1 -0
  191. ciris_engine/gui_static/_next/static/chunks/app/services/page-ae9f0bdf11d01a95.js +1 -0
  192. ciris_engine/gui_static/_next/static/chunks/app/services/page-b10feb79ca5d75e5.js +1 -0
  193. ciris_engine/gui_static/_next/static/chunks/app/sessions/page-13ebe7ef1c16ae11.js +1 -0
  194. ciris_engine/gui_static/_next/static/chunks/app/sessions/page-e6c82b16d617f785.js +1 -0
  195. ciris_engine/gui_static/_next/static/chunks/app/setup/page-0beb5f5b5a5c20fc.js +1 -0
  196. ciris_engine/gui_static/_next/static/chunks/app/setup/page-2595e729eae30c0e.js +1 -0
  197. ciris_engine/gui_static/_next/static/chunks/app/status-dashboard/page-1037c987aecc3653.js +1 -0
  198. ciris_engine/gui_static/_next/static/chunks/app/status-dashboard/page-2ffd147f6d3162ff.js +1 -0
  199. ciris_engine/gui_static/_next/static/chunks/app/system/page-2c5798d58cafcd91.js +1 -0
  200. ciris_engine/gui_static/_next/static/chunks/app/system/page-505b1ba4eceb01c3.js +1 -0
  201. ciris_engine/gui_static/_next/static/chunks/app/test-auth/page-b0cad31d5cb1b2fa.js +1 -0
  202. ciris_engine/gui_static/_next/static/chunks/app/test-auth/page-f3ecd7a8012df230.js +1 -0
  203. ciris_engine/gui_static/_next/static/chunks/app/test-login/page-f35117fdc4105801.js +1 -0
  204. ciris_engine/gui_static/_next/static/chunks/app/test-login/page-fb583a7924114906.js +1 -0
  205. ciris_engine/gui_static/_next/static/chunks/app/test-sdk/page-50f116fd76935563.js +1 -0
  206. ciris_engine/gui_static/_next/static/chunks/app/test-sdk/page-c37d8aa5ba623a44.js +1 -0
  207. ciris_engine/gui_static/_next/static/chunks/app/tools/page-429aec7a707777ef.js +1 -0
  208. ciris_engine/gui_static/_next/static/chunks/app/tools/page-5f705aad60e0c04e.js +1 -0
  209. ciris_engine/gui_static/_next/static/chunks/app/users/page-13476b8b0f3808cc.js +1 -0
  210. ciris_engine/gui_static/_next/static/chunks/app/users/page-7e500d154ed5bba4.js +1 -0
  211. ciris_engine/gui_static/_next/static/chunks/app/wa/page-cc4a9d8a5cb44d08.js +1 -0
  212. ciris_engine/gui_static/_next/static/chunks/app/wa/page-ec3e429efbc79230.js +1 -0
  213. ciris_engine/gui_static/_next/static/chunks/framework-9d29490f5ba089ba.js +1 -0
  214. ciris_engine/gui_static/_next/static/chunks/main-1f554952e47a82c4.js +1 -0
  215. ciris_engine/gui_static/_next/static/chunks/main-app-26fa8aed029082e5.js +1 -0
  216. ciris_engine/gui_static/_next/static/chunks/main-app-97b0486ef6bcef25.js +1 -0
  217. ciris_engine/gui_static/_next/static/chunks/pages/_app-6ce685456e616eb2.js +1 -0
  218. ciris_engine/gui_static/_next/static/chunks/pages/_error-d4bce98d93fe21e7.js +1 -0
  219. ciris_engine/gui_static/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  220. ciris_engine/gui_static/_next/static/chunks/webpack-fcebd240b7f8477d.js +1 -0
  221. ciris_engine/gui_static/_next/static/css/16b94b1fe0cc6e37.css +3 -0
  222. ciris_engine/gui_static/_next/static/css/77a24ceaae86deff.css +3 -0
  223. ciris_engine/gui_static/_next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  224. ciris_engine/gui_static/_next/static/media/747892c23ea88013-s.woff2 +0 -0
  225. ciris_engine/gui_static/_next/static/media/8d697b304b401681-s.woff2 +0 -0
  226. ciris_engine/gui_static/_next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  227. ciris_engine/gui_static/_next/static/media/9610d9e46709d722-s.woff2 +0 -0
  228. ciris_engine/gui_static/_next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  229. ciris_engine/gui_static/_next/static/media/d8298875641ec7d4-s.p.woff2 +0 -0
  230. ciris_engine/gui_static/account/api-keys/index.html +1 -0
  231. ciris_engine/gui_static/account/api-keys/index.txt +27 -0
  232. ciris_engine/gui_static/account/consent/index.html +1 -0
  233. ciris_engine/gui_static/account/consent/index.txt +27 -0
  234. ciris_engine/gui_static/account/index.html +1 -0
  235. ciris_engine/gui_static/account/index.txt +27 -0
  236. ciris_engine/gui_static/account/privacy/index.html +1 -0
  237. ciris_engine/gui_static/account/privacy/index.txt +27 -0
  238. ciris_engine/gui_static/account/settings/index.html +1 -0
  239. ciris_engine/gui_static/account/settings/index.txt +27 -0
  240. ciris_engine/gui_static/adapters/index.html +1 -0
  241. ciris_engine/gui_static/adapters/index.txt +27 -0
  242. ciris_engine/gui_static/agents/index.html +1 -0
  243. ciris_engine/gui_static/agents/index.txt +27 -0
  244. ciris_engine/gui_static/andrew-roberts-euBRXcx57T4-unsplash.jpg +0 -0
  245. ciris_engine/gui_static/api-demo/index.html +1 -0
  246. ciris_engine/gui_static/api-demo/index.txt +27 -0
  247. ciris_engine/gui_static/audit/index.html +1 -0
  248. ciris_engine/gui_static/audit/index.txt +27 -0
  249. ciris_engine/gui_static/billing/index.html +1 -0
  250. ciris_engine/gui_static/billing/index.txt +27 -0
  251. ciris_engine/gui_static/blurryinfo.png +0 -0
  252. ciris_engine/gui_static/chip-vincent-PkQDwfl9Flc-unsplash.jpg +0 -0
  253. ciris_engine/gui_static/ciris-architecture.svg +338 -0
  254. ciris_engine/gui_static/comms/index.html +1 -0
  255. ciris_engine/gui_static/comms/index.txt +27 -0
  256. ciris_engine/gui_static/config/index.html +1 -0
  257. ciris_engine/gui_static/config/index.txt +27 -0
  258. ciris_engine/gui_static/consent/index.html +1 -0
  259. ciris_engine/gui_static/consent/index.txt +27 -0
  260. ciris_engine/gui_static/dashboard/index.html +1 -0
  261. ciris_engine/gui_static/dashboard/index.txt +27 -0
  262. ciris_engine/gui_static/docs/index.html +1 -0
  263. ciris_engine/gui_static/docs/index.txt +27 -0
  264. ciris_engine/gui_static/eric.png +0 -0
  265. ciris_engine/gui_static/file.svg +1 -0
  266. ciris_engine/gui_static/globe.svg +1 -0
  267. ciris_engine/gui_static/index.html +1 -0
  268. ciris_engine/gui_static/index.txt +27 -0
  269. ciris_engine/gui_static/infogfx-1@2x.png +0 -0
  270. ciris_engine/gui_static/infogfx-2.png +0 -0
  271. ciris_engine/gui_static/infogfx-dark-1.png +0 -0
  272. ciris_engine/gui_static/kelly-vohs-soSTXmIxTDU-unsplash.jpg +0 -0
  273. ciris_engine/gui_static/login/index.html +1 -0
  274. ciris_engine/gui_static/login/index.txt +27 -0
  275. ciris_engine/gui_static/logs/index.html +1 -0
  276. ciris_engine/gui_static/logs/index.txt +27 -0
  277. ciris_engine/gui_static/memory/index.html +1 -0
  278. ciris_engine/gui_static/memory/index.txt +27 -0
  279. ciris_engine/gui_static/nathan-farrish-ArcTfEoBgzs-unsplash.jpg +0 -0
  280. ciris_engine/gui_static/next.svg +1 -0
  281. ciris_engine/gui_static/overview.svg +512 -0
  282. ciris_engine/gui_static/overview1.svg +407 -0
  283. ciris_engine/gui_static/overview2.svg +370 -0
  284. ciris_engine/gui_static/pipeline-visualization.svg +278 -0
  285. ciris_engine/gui_static/privacy-policy.html +160 -0
  286. ciris_engine/gui_static/runtime/index.html +8 -0
  287. ciris_engine/gui_static/runtime/index.txt +27 -0
  288. ciris_engine/gui_static/services/index.html +1 -0
  289. ciris_engine/gui_static/services/index.txt +27 -0
  290. ciris_engine/gui_static/sessions/index.html +1 -0
  291. ciris_engine/gui_static/sessions/index.txt +27 -0
  292. ciris_engine/gui_static/setup/index.html +1 -0
  293. ciris_engine/gui_static/setup/index.txt +27 -0
  294. ciris_engine/gui_static/status-dashboard/index.html +1 -0
  295. ciris_engine/gui_static/status-dashboard/index.txt +27 -0
  296. ciris_engine/gui_static/system/index.html +1 -0
  297. ciris_engine/gui_static/system/index.txt +27 -0
  298. ciris_engine/gui_static/terms-of-service.html +174 -0
  299. ciris_engine/gui_static/test-auth/index.html +1 -0
  300. ciris_engine/gui_static/test-auth/index.txt +27 -0
  301. ciris_engine/gui_static/test-login/index.html +1 -0
  302. ciris_engine/gui_static/test-login/index.txt +27 -0
  303. ciris_engine/gui_static/test-sdk/index.html +1 -0
  304. ciris_engine/gui_static/test-sdk/index.txt +27 -0
  305. ciris_engine/gui_static/tools/index.html +1 -0
  306. ciris_engine/gui_static/tools/index.txt +27 -0
  307. ciris_engine/gui_static/users/index.html +1 -0
  308. ciris_engine/gui_static/users/index.txt +27 -0
  309. ciris_engine/gui_static/vercel.svg +1 -0
  310. ciris_engine/gui_static/videos/video1.mp4 +0 -0
  311. ciris_engine/gui_static/videos/video3.mp4 +0 -0
  312. ciris_engine/gui_static/wa/index.html +1 -0
  313. ciris_engine/gui_static/wa/index.txt +27 -0
  314. ciris_engine/gui_static/window.svg +1 -0
  315. ciris_engine/logic/__init__.py +8 -0
  316. ciris_engine/logic/adapters/__init__.py +74 -0
  317. ciris_engine/logic/adapters/api/__init__.py +5 -0
  318. ciris_engine/logic/adapters/api/adapter.py +1037 -0
  319. ciris_engine/logic/adapters/api/api_communication.py +370 -0
  320. ciris_engine/logic/adapters/api/api_document.py +330 -0
  321. ciris_engine/logic/adapters/api/api_observer.py +24 -0
  322. ciris_engine/logic/adapters/api/api_runtime_control.py +388 -0
  323. ciris_engine/logic/adapters/api/api_tools.py +299 -0
  324. ciris_engine/logic/adapters/api/api_vision.py +215 -0
  325. ciris_engine/logic/adapters/api/app.py +272 -0
  326. ciris_engine/logic/adapters/api/auth.py +159 -0
  327. ciris_engine/logic/adapters/api/config.py +101 -0
  328. ciris_engine/logic/adapters/api/constants.py +55 -0
  329. ciris_engine/logic/adapters/api/dependencies/__init__.py +1 -0
  330. ciris_engine/logic/adapters/api/dependencies/auth.py +260 -0
  331. ciris_engine/logic/adapters/api/endpoints/__init__.py +1 -0
  332. ciris_engine/logic/adapters/api/endpoints/emergency.py +86 -0
  333. ciris_engine/logic/adapters/api/middleware/__init__.py +1 -0
  334. ciris_engine/logic/adapters/api/middleware/rate_limiter.py +302 -0
  335. ciris_engine/logic/adapters/api/models.py +29 -0
  336. ciris_engine/logic/adapters/api/routes/__init__.py +52 -0
  337. ciris_engine/logic/adapters/api/routes/agent.py +1762 -0
  338. ciris_engine/logic/adapters/api/routes/audit.py +707 -0
  339. ciris_engine/logic/adapters/api/routes/auth.py +1745 -0
  340. ciris_engine/logic/adapters/api/routes/billing.py +895 -0
  341. ciris_engine/logic/adapters/api/routes/config.py +329 -0
  342. ciris_engine/logic/adapters/api/routes/connectors.py +534 -0
  343. ciris_engine/logic/adapters/api/routes/consent.py +637 -0
  344. ciris_engine/logic/adapters/api/routes/dsar.py +637 -0
  345. ciris_engine/logic/adapters/api/routes/dsar_multi_source.py +484 -0
  346. ciris_engine/logic/adapters/api/routes/emergency.py +302 -0
  347. ciris_engine/logic/adapters/api/routes/memory.py +733 -0
  348. ciris_engine/logic/adapters/api/routes/memory_filters.py +230 -0
  349. ciris_engine/logic/adapters/api/routes/memory_models.py +112 -0
  350. ciris_engine/logic/adapters/api/routes/memory_queries.py +236 -0
  351. ciris_engine/logic/adapters/api/routes/memory_query_helpers.py +394 -0
  352. ciris_engine/logic/adapters/api/routes/memory_visualization.py +359 -0
  353. ciris_engine/logic/adapters/api/routes/memory_visualization_helpers.py +110 -0
  354. ciris_engine/logic/adapters/api/routes/partnership.py +541 -0
  355. ciris_engine/logic/adapters/api/routes/setup.py +1374 -0
  356. ciris_engine/logic/adapters/api/routes/system.py +3049 -0
  357. ciris_engine/logic/adapters/api/routes/system_extensions.py +952 -0
  358. ciris_engine/logic/adapters/api/routes/telemetry.py +1987 -0
  359. ciris_engine/logic/adapters/api/routes/telemetry_converters.py +141 -0
  360. ciris_engine/logic/adapters/api/routes/telemetry_helpers.py +111 -0
  361. ciris_engine/logic/adapters/api/routes/telemetry_logs_reader.py +280 -0
  362. ciris_engine/logic/adapters/api/routes/telemetry_metrics.py +131 -0
  363. ciris_engine/logic/adapters/api/routes/telemetry_models.py +190 -0
  364. ciris_engine/logic/adapters/api/routes/telemetry_otlp.py +878 -0
  365. ciris_engine/logic/adapters/api/routes/telemetry_resource_helpers.py +191 -0
  366. ciris_engine/logic/adapters/api/routes/tickets.py +541 -0
  367. ciris_engine/logic/adapters/api/routes/tools.py +556 -0
  368. ciris_engine/logic/adapters/api/routes/transparency.py +281 -0
  369. ciris_engine/logic/adapters/api/routes/users.py +981 -0
  370. ciris_engine/logic/adapters/api/routes/verification.py +373 -0
  371. ciris_engine/logic/adapters/api/routes/wa.py +369 -0
  372. ciris_engine/logic/adapters/api/service_configuration.py +177 -0
  373. ciris_engine/logic/adapters/api/services/__init__.py +1 -0
  374. ciris_engine/logic/adapters/api/services/auth_service.py +1417 -0
  375. ciris_engine/logic/adapters/api/services/oauth_security.py +68 -0
  376. ciris_engine/logic/adapters/base.py +141 -0
  377. ciris_engine/logic/adapters/base_adapter.py +73 -0
  378. ciris_engine/logic/adapters/base_observer.py +1141 -0
  379. ciris_engine/logic/adapters/base_vision.py +312 -0
  380. ciris_engine/logic/adapters/cirisnode_client.py +307 -0
  381. ciris_engine/logic/adapters/cli/__init__.py +3 -0
  382. ciris_engine/logic/adapters/cli/adapter.py +207 -0
  383. ciris_engine/logic/adapters/cli/cli_adapter.py +902 -0
  384. ciris_engine/logic/adapters/cli/cli_observer.py +268 -0
  385. ciris_engine/logic/adapters/cli/cli_tools.py +427 -0
  386. ciris_engine/logic/adapters/cli/cli_wa_service.py +134 -0
  387. ciris_engine/logic/adapters/cli/config.py +73 -0
  388. ciris_engine/logic/adapters/discord/__init__.py +3 -0
  389. ciris_engine/logic/adapters/discord/adapter.py +783 -0
  390. ciris_engine/logic/adapters/discord/ciris_discord_client.py +159 -0
  391. ciris_engine/logic/adapters/discord/config.py +177 -0
  392. ciris_engine/logic/adapters/discord/constants.py +185 -0
  393. ciris_engine/logic/adapters/discord/discord-stubs.pyi +50 -0
  394. ciris_engine/logic/adapters/discord/discord_adapter.py +1584 -0
  395. ciris_engine/logic/adapters/discord/discord_audit.py +150 -0
  396. ciris_engine/logic/adapters/discord/discord_channel_manager.py +351 -0
  397. ciris_engine/logic/adapters/discord/discord_connection_manager.py +313 -0
  398. ciris_engine/logic/adapters/discord/discord_embed_formatter.py +369 -0
  399. ciris_engine/logic/adapters/discord/discord_error_classifier.py +302 -0
  400. ciris_engine/logic/adapters/discord/discord_error_handler.py +316 -0
  401. ciris_engine/logic/adapters/discord/discord_guidance_handler.py +460 -0
  402. ciris_engine/logic/adapters/discord/discord_message_handler.py +207 -0
  403. ciris_engine/logic/adapters/discord/discord_observer.py +670 -0
  404. ciris_engine/logic/adapters/discord/discord_rate_limiter.py +249 -0
  405. ciris_engine/logic/adapters/discord/discord_reaction_handler.py +278 -0
  406. ciris_engine/logic/adapters/discord/discord_tool_handler.py +465 -0
  407. ciris_engine/logic/adapters/discord/discord_tool_service.py +790 -0
  408. ciris_engine/logic/adapters/discord/discord_tools.py +90 -0
  409. ciris_engine/logic/adapters/discord/discord_vision_helper.py +148 -0
  410. ciris_engine/logic/adapters/discord/py.typed +0 -0
  411. ciris_engine/logic/adapters/document_parser.py +320 -0
  412. ciris_engine/logic/audit/__init__.py +10 -0
  413. ciris_engine/logic/audit/hash_chain.py +313 -0
  414. ciris_engine/logic/audit/signature_manager.py +352 -0
  415. ciris_engine/logic/audit/verifier.py +408 -0
  416. ciris_engine/logic/buses/__init__.py +21 -0
  417. ciris_engine/logic/buses/base_bus.py +178 -0
  418. ciris_engine/logic/buses/bus_manager.py +121 -0
  419. ciris_engine/logic/buses/communication_bus.py +387 -0
  420. ciris_engine/logic/buses/llm_bus.py +722 -0
  421. ciris_engine/logic/buses/memory_bus.py +577 -0
  422. ciris_engine/logic/buses/prohibitions.py +502 -0
  423. ciris_engine/logic/buses/runtime_control_bus.py +539 -0
  424. ciris_engine/logic/buses/tool_bus.py +482 -0
  425. ciris_engine/logic/buses/wise_bus.py +684 -0
  426. ciris_engine/logic/config/__init__.py +25 -0
  427. ciris_engine/logic/config/bootstrap.py +255 -0
  428. ciris_engine/logic/config/config_accessor.py +202 -0
  429. ciris_engine/logic/config/db_paths.py +194 -0
  430. ciris_engine/logic/config/env_utils.py +39 -0
  431. ciris_engine/logic/conscience/__init__.py +16 -0
  432. ciris_engine/logic/conscience/build_deferral_package.py +0 -0
  433. ciris_engine/logic/conscience/core.py +688 -0
  434. ciris_engine/logic/conscience/interface.py +33 -0
  435. ciris_engine/logic/conscience/registry.py +76 -0
  436. ciris_engine/logic/conscience/thought_depth_guardrail.py +231 -0
  437. ciris_engine/logic/conscience/updated_status_conscience.py +156 -0
  438. ciris_engine/logic/context/__init__.py +10 -0
  439. ciris_engine/logic/context/batch_context.py +550 -0
  440. ciris_engine/logic/context/builder.py +149 -0
  441. ciris_engine/logic/context/channel_resolution.py +136 -0
  442. ciris_engine/logic/context/secrets_snapshot.py +52 -0
  443. ciris_engine/logic/context/system_snapshot.py +116 -0
  444. ciris_engine/logic/context/system_snapshot_helpers.py +1651 -0
  445. ciris_engine/logic/covenant/__init__.py +33 -0
  446. ciris_engine/logic/covenant/executor.py +303 -0
  447. ciris_engine/logic/covenant/extractor.py +382 -0
  448. ciris_engine/logic/covenant/handler.py +241 -0
  449. ciris_engine/logic/covenant/verifier.py +383 -0
  450. ciris_engine/logic/dma/__init__.py +15 -0
  451. ciris_engine/logic/dma/action_selection/__init__.py +11 -0
  452. ciris_engine/logic/dma/action_selection/action_instruction_generator.py +444 -0
  453. ciris_engine/logic/dma/action_selection/context_builder.py +508 -0
  454. ciris_engine/logic/dma/action_selection/faculty_integration.py +193 -0
  455. ciris_engine/logic/dma/action_selection/special_cases.py +132 -0
  456. ciris_engine/logic/dma/action_selection_pdma.py +365 -0
  457. ciris_engine/logic/dma/base_dma.py +335 -0
  458. ciris_engine/logic/dma/csdma.py +239 -0
  459. ciris_engine/logic/dma/dma_executor.py +575 -0
  460. ciris_engine/logic/dma/dsdma_base.py +410 -0
  461. ciris_engine/logic/dma/exceptions.py +4 -0
  462. ciris_engine/logic/dma/factory.py +150 -0
  463. ciris_engine/logic/dma/pdma.py +120 -0
  464. ciris_engine/logic/dma/prompt_loader.py +189 -0
  465. ciris_engine/logic/dma/prompts/action_selection_pdma.yml +58 -0
  466. ciris_engine/logic/dma/prompts/csdma_common_sense.yml +28 -0
  467. ciris_engine/logic/dma/prompts/dsdma_base.yml +17 -0
  468. ciris_engine/logic/dma/prompts/pdma_ethical.yml +42 -0
  469. ciris_engine/logic/formatters/__init__.py +26 -0
  470. ciris_engine/logic/formatters/crisis_resources.py +80 -0
  471. ciris_engine/logic/formatters/escalation.py +21 -0
  472. ciris_engine/logic/formatters/identity.py +224 -0
  473. ciris_engine/logic/formatters/prompt_blocks.py +64 -0
  474. ciris_engine/logic/formatters/system_snapshot.py +193 -0
  475. ciris_engine/logic/formatters/user_profiles.py +108 -0
  476. ciris_engine/logic/handlers/__init__.py +1 -0
  477. ciris_engine/logic/handlers/control/__init__.py +1 -0
  478. ciris_engine/logic/handlers/control/defer_handler.py +195 -0
  479. ciris_engine/logic/handlers/control/ponder_handler.py +154 -0
  480. ciris_engine/logic/handlers/control/reject_handler.py +81 -0
  481. ciris_engine/logic/handlers/external/__init__.py +1 -0
  482. ciris_engine/logic/handlers/external/observe_handler.py +154 -0
  483. ciris_engine/logic/handlers/external/speak_handler.py +250 -0
  484. ciris_engine/logic/handlers/external/tool_handler.py +148 -0
  485. ciris_engine/logic/handlers/memory/__init__.py +1 -0
  486. ciris_engine/logic/handlers/memory/forget_handler.py +107 -0
  487. ciris_engine/logic/handlers/memory/memorize_handler.py +391 -0
  488. ciris_engine/logic/handlers/memory/recall_handler.py +213 -0
  489. ciris_engine/logic/handlers/terminal/__init__.py +1 -0
  490. ciris_engine/logic/handlers/terminal/task_complete_handler.py +299 -0
  491. ciris_engine/logic/infrastructure/__init__.py +1 -0
  492. ciris_engine/logic/infrastructure/handlers/__init__.py +8 -0
  493. ciris_engine/logic/infrastructure/handlers/action_dispatcher.py +382 -0
  494. ciris_engine/logic/infrastructure/handlers/base_handler.py +450 -0
  495. ciris_engine/logic/infrastructure/handlers/exceptions.py +2 -0
  496. ciris_engine/logic/infrastructure/handlers/handler_registry.py +59 -0
  497. ciris_engine/logic/infrastructure/handlers/helpers.py +55 -0
  498. ciris_engine/logic/infrastructure/step_streaming.py +149 -0
  499. ciris_engine/logic/infrastructure/sub_services/__init__.py +1 -0
  500. ciris_engine/logic/infrastructure/sub_services/identity_variance_monitor.py +1035 -0
  501. ciris_engine/logic/infrastructure/sub_services/pattern_analysis_loop.py +758 -0
  502. ciris_engine/logic/infrastructure/sub_services/wa_cli_bootstrap.py +229 -0
  503. ciris_engine/logic/infrastructure/sub_services/wa_cli_display.py +176 -0
  504. ciris_engine/logic/infrastructure/sub_services/wa_cli_oauth.py +404 -0
  505. ciris_engine/logic/infrastructure/sub_services/wa_cli_wizard.py +181 -0
  506. ciris_engine/logic/persistence/__init__.py +130 -0
  507. ciris_engine/logic/persistence/analytics.py +97 -0
  508. ciris_engine/logic/persistence/db/__init__.py +28 -0
  509. ciris_engine/logic/persistence/db/core.py +520 -0
  510. ciris_engine/logic/persistence/db/dialect.py +380 -0
  511. ciris_engine/logic/persistence/db/execution_helpers.py +216 -0
  512. ciris_engine/logic/persistence/db/migration_runner.py +191 -0
  513. ciris_engine/logic/persistence/db/operations.py +313 -0
  514. ciris_engine/logic/persistence/db/query_builder.py +232 -0
  515. ciris_engine/logic/persistence/db/retry.py +154 -0
  516. ciris_engine/logic/persistence/db/setup.py +18 -0
  517. ciris_engine/logic/persistence/migrations/postgres/001_initial_schema.sql +4 -0
  518. ciris_engine/logic/persistence/migrations/postgres/002_add_retry_status.sql +3 -0
  519. ciris_engine/logic/persistence/migrations/postgres/003_add_task_update_tracking.sql +8 -0
  520. ciris_engine/logic/persistence/migrations/postgres/004_add_occurrence_id.sql +54 -0
  521. ciris_engine/logic/persistence/migrations/postgres/005_add_consolidation_locks.sql +22 -0
  522. ciris_engine/logic/persistence/migrations/postgres/006_add_correlation_id_unique_index.sql +16 -0
  523. ciris_engine/logic/persistence/migrations/postgres/007_add_dsar_tickets.sql +39 -0
  524. ciris_engine/logic/persistence/migrations/postgres/008_rename_to_tickets_add_sop.sql +123 -0
  525. ciris_engine/logic/persistence/migrations/postgres/009_add_ticket_status_columns.sql +39 -0
  526. ciris_engine/logic/persistence/migrations/postgres/010_add_images_to_tasks.sql +5 -0
  527. ciris_engine/logic/persistence/migrations/sqlite/001_initial_schema.sql +357 -0
  528. ciris_engine/logic/persistence/migrations/sqlite/002_add_retry_status.sql +3 -0
  529. ciris_engine/logic/persistence/migrations/sqlite/003_add_task_update_tracking.sql +8 -0
  530. ciris_engine/logic/persistence/migrations/sqlite/004_add_occurrence_id.sql +45 -0
  531. ciris_engine/logic/persistence/migrations/sqlite/005_add_consolidation_locks.sql +22 -0
  532. ciris_engine/logic/persistence/migrations/sqlite/006_add_correlation_id_unique_index.sql +16 -0
  533. ciris_engine/logic/persistence/migrations/sqlite/007_add_dsar_tickets.sql +39 -0
  534. ciris_engine/logic/persistence/migrations/sqlite/008_rename_to_tickets_add_sop.sql +120 -0
  535. ciris_engine/logic/persistence/migrations/sqlite/009_add_ticket_status_columns.sql +129 -0
  536. ciris_engine/logic/persistence/migrations/sqlite/010_add_images_to_tasks.sql +17 -0
  537. ciris_engine/logic/persistence/models/__init__.py +141 -0
  538. ciris_engine/logic/persistence/models/correlations.py +881 -0
  539. ciris_engine/logic/persistence/models/deferral.py +68 -0
  540. ciris_engine/logic/persistence/models/dsar.py +286 -0
  541. ciris_engine/logic/persistence/models/graph.py +362 -0
  542. ciris_engine/logic/persistence/models/identity.py +264 -0
  543. ciris_engine/logic/persistence/models/queue_status.py +139 -0
  544. ciris_engine/logic/persistence/models/tasks.py +1043 -0
  545. ciris_engine/logic/persistence/models/thoughts.py +400 -0
  546. ciris_engine/logic/persistence/models/tickets.py +518 -0
  547. ciris_engine/logic/persistence/stores/__init__.py +13 -0
  548. ciris_engine/logic/persistence/stores/auth_helpers.py +117 -0
  549. ciris_engine/logic/persistence/stores/authentication_store.py +414 -0
  550. ciris_engine/logic/persistence/utils.py +212 -0
  551. ciris_engine/logic/processors/__init__.py +30 -0
  552. ciris_engine/logic/processors/core/__init__.py +1 -0
  553. ciris_engine/logic/processors/core/base_processor.py +280 -0
  554. ciris_engine/logic/processors/core/main_processor.py +1777 -0
  555. ciris_engine/logic/processors/core/step_decorators.py +1583 -0
  556. ciris_engine/logic/processors/core/thought_processor/__init__.py +20 -0
  557. ciris_engine/logic/processors/core/thought_processor/action_execution.py +49 -0
  558. ciris_engine/logic/processors/core/thought_processor/conscience_execution.py +382 -0
  559. ciris_engine/logic/processors/core/thought_processor/finalize_action.py +66 -0
  560. ciris_engine/logic/processors/core/thought_processor/gather_context.py +120 -0
  561. ciris_engine/logic/processors/core/thought_processor/main.py +920 -0
  562. ciris_engine/logic/processors/core/thought_processor/perform_aspdma.py +86 -0
  563. ciris_engine/logic/processors/core/thought_processor/perform_dmas.py +106 -0
  564. ciris_engine/logic/processors/core/thought_processor/recursive_processing.py +237 -0
  565. ciris_engine/logic/processors/core/thought_processor/round_complete.py +52 -0
  566. ciris_engine/logic/processors/core/thought_processor/start_round.py +64 -0
  567. ciris_engine/logic/processors/exceptions.py +59 -0
  568. ciris_engine/logic/processors/states/__init__.py +1 -0
  569. ciris_engine/logic/processors/states/dream_processor.py +1381 -0
  570. ciris_engine/logic/processors/states/play_processor.py +141 -0
  571. ciris_engine/logic/processors/states/shutdown_processor.py +623 -0
  572. ciris_engine/logic/processors/states/solitude_processor.py +305 -0
  573. ciris_engine/logic/processors/states/wakeup_processor.py +802 -0
  574. ciris_engine/logic/processors/states/work_processor.py +742 -0
  575. ciris_engine/logic/processors/support/__init__.py +1 -0
  576. ciris_engine/logic/processors/support/dma_orchestrator.py +336 -0
  577. ciris_engine/logic/processors/support/processing_queue.py +133 -0
  578. ciris_engine/logic/processors/support/shutdown_condition_evaluator.py +294 -0
  579. ciris_engine/logic/processors/support/state_manager.py +358 -0
  580. ciris_engine/logic/processors/support/task_manager.py +303 -0
  581. ciris_engine/logic/processors/support/thought_escalation.py +116 -0
  582. ciris_engine/logic/processors/support/thought_manager.py +328 -0
  583. ciris_engine/logic/processors/support/thought_manager_enhanced.py +105 -0
  584. ciris_engine/logic/registries/__init__.py +34 -0
  585. ciris_engine/logic/registries/base.py +653 -0
  586. ciris_engine/logic/registries/circuit_breaker.py +275 -0
  587. ciris_engine/logic/registries/typed_registries.py +184 -0
  588. ciris_engine/logic/runtime/__init__.py +7 -0
  589. ciris_engine/logic/runtime/adapter_loader.py +261 -0
  590. ciris_engine/logic/runtime/adapter_manager.py +1053 -0
  591. ciris_engine/logic/runtime/ciris_runtime.py +2342 -0
  592. ciris_engine/logic/runtime/ciris_runtime_helpers.py +923 -0
  593. ciris_engine/logic/runtime/component_builder.py +361 -0
  594. ciris_engine/logic/runtime/identity_manager.py +219 -0
  595. ciris_engine/logic/runtime/module_loader.py +207 -0
  596. ciris_engine/logic/runtime/prevent_sideeffects.py +30 -0
  597. ciris_engine/logic/runtime/runtime_interface.py +23 -0
  598. ciris_engine/logic/runtime/service_initializer.py +1623 -0
  599. ciris_engine/logic/secrets/__init__.py +30 -0
  600. ciris_engine/logic/secrets/encryption.py +175 -0
  601. ciris_engine/logic/secrets/filter.py +295 -0
  602. ciris_engine/logic/secrets/service.py +652 -0
  603. ciris_engine/logic/secrets/store.py +669 -0
  604. ciris_engine/logic/services/__init__.py +1 -0
  605. ciris_engine/logic/services/adaptation/__init__.py +3 -0
  606. ciris_engine/logic/services/base_graph_service.py +142 -0
  607. ciris_engine/logic/services/base_infrastructure_service.py +69 -0
  608. ciris_engine/logic/services/base_scheduled_service.py +136 -0
  609. ciris_engine/logic/services/base_service.py +247 -0
  610. ciris_engine/logic/services/governance/__init__.py +3 -0
  611. ciris_engine/logic/services/governance/adaptive_filter/__init__.py +14 -0
  612. ciris_engine/logic/services/governance/adaptive_filter/service.py +818 -0
  613. ciris_engine/logic/services/governance/consent/__init__.py +53 -0
  614. ciris_engine/logic/services/governance/consent/air.py +403 -0
  615. ciris_engine/logic/services/governance/consent/decay.py +324 -0
  616. ciris_engine/logic/services/governance/consent/dsar_automation.py +589 -0
  617. ciris_engine/logic/services/governance/consent/exceptions.py +106 -0
  618. ciris_engine/logic/services/governance/consent/metrics.py +270 -0
  619. ciris_engine/logic/services/governance/consent/partnership.py +533 -0
  620. ciris_engine/logic/services/governance/consent/service.py +1256 -0
  621. ciris_engine/logic/services/governance/dsar/__init__.py +29 -0
  622. ciris_engine/logic/services/governance/dsar/orchestrator.py +977 -0
  623. ciris_engine/logic/services/governance/dsar/schemas.py +141 -0
  624. ciris_engine/logic/services/governance/dsar/signature_service.py +283 -0
  625. ciris_engine/logic/services/governance/self_observation/__init__.py +20 -0
  626. ciris_engine/logic/services/governance/self_observation/service.py +1153 -0
  627. ciris_engine/logic/services/governance/visibility/__init__.py +17 -0
  628. ciris_engine/logic/services/governance/visibility/service.py +512 -0
  629. ciris_engine/logic/services/governance/wise_authority/__init__.py +15 -0
  630. ciris_engine/logic/services/governance/wise_authority/service.py +827 -0
  631. ciris_engine/logic/services/graph/__init__.py +5 -0
  632. ciris_engine/logic/services/graph/audit_service/__init__.py +5 -0
  633. ciris_engine/logic/services/graph/audit_service/service.py +1675 -0
  634. ciris_engine/logic/services/graph/base.py +208 -0
  635. ciris_engine/logic/services/graph/config_service/__init__.py +5 -0
  636. ciris_engine/logic/services/graph/config_service/service.py +372 -0
  637. ciris_engine/logic/services/graph/incident_service/__init__.py +5 -0
  638. ciris_engine/logic/services/graph/incident_service/service.py +803 -0
  639. ciris_engine/logic/services/graph/memory_service.py +1120 -0
  640. ciris_engine/logic/services/graph/telemetry_service/__init__.py +5 -0
  641. ciris_engine/logic/services/graph/telemetry_service/exceptions.py +104 -0
  642. ciris_engine/logic/services/graph/telemetry_service/helpers.py +1337 -0
  643. ciris_engine/logic/services/graph/telemetry_service/service.py +2429 -0
  644. ciris_engine/logic/services/graph/tsdb_consolidation/__init__.py +17 -0
  645. ciris_engine/logic/services/graph/tsdb_consolidation/aggregation_helpers.py +355 -0
  646. ciris_engine/logic/services/graph/tsdb_consolidation/cleanup_helpers.py +438 -0
  647. ciris_engine/logic/services/graph/tsdb_consolidation/compressor.py +260 -0
  648. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/__init__.py +27 -0
  649. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/audit.py +326 -0
  650. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/conversation.py +291 -0
  651. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/memory.py +197 -0
  652. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/metrics.py +251 -0
  653. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/task.py +257 -0
  654. ciris_engine/logic/services/graph/tsdb_consolidation/consolidators/trace.py +363 -0
  655. ciris_engine/logic/services/graph/tsdb_consolidation/data_converter.py +545 -0
  656. ciris_engine/logic/services/graph/tsdb_consolidation/date_calculation_helpers.py +193 -0
  657. ciris_engine/logic/services/graph/tsdb_consolidation/db_query_helpers.py +296 -0
  658. ciris_engine/logic/services/graph/tsdb_consolidation/edge_helpers.py +92 -0
  659. ciris_engine/logic/services/graph/tsdb_consolidation/edge_manager.py +896 -0
  660. ciris_engine/logic/services/graph/tsdb_consolidation/extensive_helpers.py +322 -0
  661. ciris_engine/logic/services/graph/tsdb_consolidation/period_manager.py +152 -0
  662. ciris_engine/logic/services/graph/tsdb_consolidation/profound_helpers.py +277 -0
  663. ciris_engine/logic/services/graph/tsdb_consolidation/query_manager.py +812 -0
  664. ciris_engine/logic/services/graph/tsdb_consolidation/service.py +1692 -0
  665. ciris_engine/logic/services/graph/tsdb_consolidation/sql_builders.py +363 -0
  666. ciris_engine/logic/services/infrastructure/__init__.py +1 -0
  667. ciris_engine/logic/services/infrastructure/authentication/__init__.py +5 -0
  668. ciris_engine/logic/services/infrastructure/authentication/service.py +1634 -0
  669. ciris_engine/logic/services/infrastructure/database_maintenance/__init__.py +15 -0
  670. ciris_engine/logic/services/infrastructure/database_maintenance/service.py +764 -0
  671. ciris_engine/logic/services/infrastructure/resource_monitor/__init__.py +7 -0
  672. ciris_engine/logic/services/infrastructure/resource_monitor/ciris_billing_provider.py +755 -0
  673. ciris_engine/logic/services/infrastructure/resource_monitor/service.py +409 -0
  674. ciris_engine/logic/services/infrastructure/resource_monitor/simple_credit_provider.py +129 -0
  675. ciris_engine/logic/services/lifecycle/__init__.py +3 -0
  676. ciris_engine/logic/services/lifecycle/initialization/__init__.py +10 -0
  677. ciris_engine/logic/services/lifecycle/initialization/service.py +312 -0
  678. ciris_engine/logic/services/lifecycle/scheduler/__init__.py +5 -0
  679. ciris_engine/logic/services/lifecycle/scheduler/service.py +607 -0
  680. ciris_engine/logic/services/lifecycle/shutdown/__init__.py +9 -0
  681. ciris_engine/logic/services/lifecycle/shutdown/service.py +378 -0
  682. ciris_engine/logic/services/lifecycle/time/__init__.py +15 -0
  683. ciris_engine/logic/services/lifecycle/time/service.py +259 -0
  684. ciris_engine/logic/services/memory_service/__init__.py +8 -0
  685. ciris_engine/logic/services/mixins/__init__.py +13 -0
  686. ciris_engine/logic/services/mixins/example_usage.py +200 -0
  687. ciris_engine/logic/services/mixins/request_metrics.py +179 -0
  688. ciris_engine/logic/services/runtime/__init__.py +3 -0
  689. ciris_engine/logic/services/runtime/adapter_configuration/__init__.py +16 -0
  690. ciris_engine/logic/services/runtime/adapter_configuration/service.py +674 -0
  691. ciris_engine/logic/services/runtime/adapter_configuration/session.py +67 -0
  692. ciris_engine/logic/services/runtime/control_service/__init__.py +5 -0
  693. ciris_engine/logic/services/runtime/control_service/service.py +2269 -0
  694. ciris_engine/logic/services/runtime/llm_service/__init__.py +14 -0
  695. ciris_engine/logic/services/runtime/llm_service/pricing_calculator.py +279 -0
  696. ciris_engine/logic/services/runtime/llm_service/service.py +930 -0
  697. ciris_engine/logic/services/tools/__init__.py +5 -0
  698. ciris_engine/logic/services/tools/core_tool_service/__init__.py +8 -0
  699. ciris_engine/logic/services/tools/core_tool_service/service.py +852 -0
  700. ciris_engine/logic/setup/__init__.py +1 -0
  701. ciris_engine/logic/setup/first_run.py +250 -0
  702. ciris_engine/logic/setup/wizard.py +327 -0
  703. ciris_engine/logic/telemetry/__init__.py +46 -0
  704. ciris_engine/logic/telemetry/core.py +239 -0
  705. ciris_engine/logic/telemetry/hot_cold_config.py +133 -0
  706. ciris_engine/logic/telemetry/log_collector.py +190 -0
  707. ciris_engine/logic/telemetry/resource_monitor.py +7 -0
  708. ciris_engine/logic/telemetry/security.py +79 -0
  709. ciris_engine/logic/utils/__init__.py +18 -0
  710. ciris_engine/logic/utils/channel_utils.py +75 -0
  711. ciris_engine/logic/utils/consent/__init__.py +1 -0
  712. ciris_engine/logic/utils/consent/partnership_utils.py +172 -0
  713. ciris_engine/logic/utils/constants.py +92 -0
  714. ciris_engine/logic/utils/context_utils.py +145 -0
  715. ciris_engine/logic/utils/directory_setup.py +533 -0
  716. ciris_engine/logic/utils/graphql_context_provider.py +152 -0
  717. ciris_engine/logic/utils/identity_resolution.py +843 -0
  718. ciris_engine/logic/utils/incident_capture_handler.py +303 -0
  719. ciris_engine/logic/utils/initialization_manager.py +74 -0
  720. ciris_engine/logic/utils/jsondict_helpers.py +290 -0
  721. ciris_engine/logic/utils/log_sanitizer.py +97 -0
  722. ciris_engine/logic/utils/logging_config.py +151 -0
  723. ciris_engine/logic/utils/observability_decorators.py +544 -0
  724. ciris_engine/logic/utils/occurrence_utils.py +155 -0
  725. ciris_engine/logic/utils/path_resolution.py +281 -0
  726. ciris_engine/logic/utils/platform_detection.py +286 -0
  727. ciris_engine/logic/utils/privacy.py +266 -0
  728. ciris_engine/logic/utils/profile_loader.py +124 -0
  729. ciris_engine/logic/utils/profile_manager.py +16 -0
  730. ciris_engine/logic/utils/runtime_utils.py +69 -0
  731. ciris_engine/logic/utils/shutdown_manager.py +107 -0
  732. ciris_engine/logic/utils/task_formatters.py +60 -0
  733. ciris_engine/logic/utils/task_thought_factory.py +404 -0
  734. ciris_engine/logic/utils/thought_utils.py +54 -0
  735. ciris_engine/logic/utils/user_utils.py +70 -0
  736. ciris_engine/protocols/__init__.py +0 -0
  737. ciris_engine/protocols/adapters/__init__.py +35 -0
  738. ciris_engine/protocols/adapters/base.py +149 -0
  739. ciris_engine/protocols/adapters/configurable.py +265 -0
  740. ciris_engine/protocols/adapters/message.py +90 -0
  741. ciris_engine/protocols/audit/__init__.py +1 -0
  742. ciris_engine/protocols/buses/__init__.py +1 -0
  743. ciris_engine/protocols/config/__init__.py +1 -0
  744. ciris_engine/protocols/conscience/__init__.py +1 -0
  745. ciris_engine/protocols/consent.py +88 -0
  746. ciris_engine/protocols/context/__init__.py +1 -0
  747. ciris_engine/protocols/data/__init__.py +1 -0
  748. ciris_engine/protocols/dma/__init__.py +1 -0
  749. ciris_engine/protocols/dma/base.py +107 -0
  750. ciris_engine/protocols/faculties.py +34 -0
  751. ciris_engine/protocols/formatters/__init__.py +1 -0
  752. ciris_engine/protocols/handlers/__init__.py +1 -0
  753. ciris_engine/protocols/infrastructure/__init__.py +25 -0
  754. ciris_engine/protocols/infrastructure/base.py +377 -0
  755. ciris_engine/protocols/persistence/__init__.py +1 -0
  756. ciris_engine/protocols/pipeline_control.py +609 -0
  757. ciris_engine/protocols/processors/__init__.py +19 -0
  758. ciris_engine/protocols/processors/agent.py +299 -0
  759. ciris_engine/protocols/processors/base.py +130 -0
  760. ciris_engine/protocols/processors/orchestration.py +62 -0
  761. ciris_engine/protocols/registries/__init__.py +1 -0
  762. ciris_engine/protocols/runtime/__init__.py +1 -0
  763. ciris_engine/protocols/runtime/base.py +163 -0
  764. ciris_engine/protocols/secrets/__init__.py +1 -0
  765. ciris_engine/protocols/services/__init__.py +80 -0
  766. ciris_engine/protocols/services/adaptation/__init__.py +7 -0
  767. ciris_engine/protocols/services/adaptation/self_observation.py +265 -0
  768. ciris_engine/protocols/services/governance/__init__.py +20 -0
  769. ciris_engine/protocols/services/governance/communication.py +58 -0
  770. ciris_engine/protocols/services/governance/filter.py +56 -0
  771. ciris_engine/protocols/services/governance/visibility.py +32 -0
  772. ciris_engine/protocols/services/governance/wa_auth.py +192 -0
  773. ciris_engine/protocols/services/governance/wise_authority.py +75 -0
  774. ciris_engine/protocols/services/graph/__init__.py +19 -0
  775. ciris_engine/protocols/services/graph/audit.py +92 -0
  776. ciris_engine/protocols/services/graph/config.py +54 -0
  777. ciris_engine/protocols/services/graph/incident_management.py +103 -0
  778. ciris_engine/protocols/services/graph/memory.py +110 -0
  779. ciris_engine/protocols/services/graph/telemetry.py +51 -0
  780. ciris_engine/protocols/services/graph/tsdb_consolidation.py +87 -0
  781. ciris_engine/protocols/services/infrastructure/__init__.py +11 -0
  782. ciris_engine/protocols/services/infrastructure/authentication.py +159 -0
  783. ciris_engine/protocols/services/infrastructure/credit_gate.py +46 -0
  784. ciris_engine/protocols/services/infrastructure/database_maintenance.py +25 -0
  785. ciris_engine/protocols/services/infrastructure/resource_monitor.py +83 -0
  786. ciris_engine/protocols/services/lifecycle/__init__.py +13 -0
  787. ciris_engine/protocols/services/lifecycle/initialization.py +41 -0
  788. ciris_engine/protocols/services/lifecycle/scheduler.py +42 -0
  789. ciris_engine/protocols/services/lifecycle/shutdown.py +50 -0
  790. ciris_engine/protocols/services/lifecycle/time.py +31 -0
  791. ciris_engine/protocols/services/runtime/__init__.py +13 -0
  792. ciris_engine/protocols/services/runtime/llm.py +50 -0
  793. ciris_engine/protocols/services/runtime/runtime_control.py +193 -0
  794. ciris_engine/protocols/services/runtime/secrets.py +100 -0
  795. ciris_engine/protocols/services/runtime/tool.py +123 -0
  796. ciris_engine/protocols/telemetry/__init__.py +1 -0
  797. ciris_engine/protocols/utils/__init__.py +1 -0
  798. ciris_engine/schemas/__init__.py +112 -0
  799. ciris_engine/schemas/actions/__init__.py +37 -0
  800. ciris_engine/schemas/actions/parameters.py +137 -0
  801. ciris_engine/schemas/adapters/__init__.py +13 -0
  802. ciris_engine/schemas/adapters/cirisnode.py +135 -0
  803. ciris_engine/schemas/adapters/cli.py +97 -0
  804. ciris_engine/schemas/adapters/cli_tools.py +98 -0
  805. ciris_engine/schemas/adapters/discord.py +125 -0
  806. ciris_engine/schemas/adapters/graphql_core.py +144 -0
  807. ciris_engine/schemas/adapters/registration.py +47 -0
  808. ciris_engine/schemas/adapters/runtime_context.py +48 -0
  809. ciris_engine/schemas/adapters/tool_execution.py +45 -0
  810. ciris_engine/schemas/adapters/tools.py +96 -0
  811. ciris_engine/schemas/api/__init__.py +1 -0
  812. ciris_engine/schemas/api/agent.py +50 -0
  813. ciris_engine/schemas/api/audit.py +38 -0
  814. ciris_engine/schemas/api/auth.py +351 -0
  815. ciris_engine/schemas/api/config_security.py +242 -0
  816. ciris_engine/schemas/api/emergency.py +111 -0
  817. ciris_engine/schemas/api/responses.py +72 -0
  818. ciris_engine/schemas/api/runtime.py +26 -0
  819. ciris_engine/schemas/api/telemetry.py +109 -0
  820. ciris_engine/schemas/api/wa.py +90 -0
  821. ciris_engine/schemas/audit/__init__.py +13 -0
  822. ciris_engine/schemas/audit/core.py +139 -0
  823. ciris_engine/schemas/audit/hash_chain.py +58 -0
  824. ciris_engine/schemas/audit/verification.py +131 -0
  825. ciris_engine/schemas/buses/__init__.py +1 -0
  826. ciris_engine/schemas/config/__init__.py +41 -0
  827. ciris_engine/schemas/config/agent.py +279 -0
  828. ciris_engine/schemas/config/cognitive_state_behaviors.py +194 -0
  829. ciris_engine/schemas/config/default_dsar_sops.py +178 -0
  830. ciris_engine/schemas/config/essential.py +195 -0
  831. ciris_engine/schemas/config/tickets.py +86 -0
  832. ciris_engine/schemas/conscience/__init__.py +25 -0
  833. ciris_engine/schemas/conscience/context.py +34 -0
  834. ciris_engine/schemas/conscience/core.py +145 -0
  835. ciris_engine/schemas/conscience/results.py +24 -0
  836. ciris_engine/schemas/consent/__init__.py +5 -0
  837. ciris_engine/schemas/consent/core.py +404 -0
  838. ciris_engine/schemas/context/__init__.py +1 -0
  839. ciris_engine/schemas/covenant.py +382 -0
  840. ciris_engine/schemas/data/__init__.py +1 -0
  841. ciris_engine/schemas/dma/__init__.py +16 -0
  842. ciris_engine/schemas/dma/core.py +199 -0
  843. ciris_engine/schemas/dma/faculty.py +192 -0
  844. ciris_engine/schemas/dma/prompts.py +172 -0
  845. ciris_engine/schemas/dma/results.py +103 -0
  846. ciris_engine/schemas/formatters/__init__.py +1 -0
  847. ciris_engine/schemas/handlers/__init__.py +10 -0
  848. ciris_engine/schemas/handlers/context.py +119 -0
  849. ciris_engine/schemas/handlers/contexts.py +100 -0
  850. ciris_engine/schemas/handlers/core.py +167 -0
  851. ciris_engine/schemas/handlers/memory_schemas.py +67 -0
  852. ciris_engine/schemas/handlers/schemas.py +95 -0
  853. ciris_engine/schemas/identity.py +149 -0
  854. ciris_engine/schemas/infrastructure/__init__.py +1 -0
  855. ciris_engine/schemas/infrastructure/base.py +256 -0
  856. ciris_engine/schemas/infrastructure/behavioral_patterns.py +129 -0
  857. ciris_engine/schemas/infrastructure/feedback_loop.py +57 -0
  858. ciris_engine/schemas/infrastructure/identity_variance.py +141 -0
  859. ciris_engine/schemas/infrastructure/oauth.py +175 -0
  860. ciris_engine/schemas/infrastructure/wa_cli_wizard.py +54 -0
  861. ciris_engine/schemas/persistence/__init__.py +34 -0
  862. ciris_engine/schemas/persistence/core.py +140 -0
  863. ciris_engine/schemas/persistence/correlations.py +73 -0
  864. ciris_engine/schemas/persistence/postgres/__init__.py +1 -0
  865. ciris_engine/schemas/persistence/postgres/tables.py +280 -0
  866. ciris_engine/schemas/persistence/sqlite/__init__.py +1 -0
  867. ciris_engine/schemas/persistence/sqlite/tables.py +281 -0
  868. ciris_engine/schemas/platform.py +149 -0
  869. ciris_engine/schemas/processors/__init__.py +26 -0
  870. ciris_engine/schemas/processors/base.py +130 -0
  871. ciris_engine/schemas/processors/cognitive.py +77 -0
  872. ciris_engine/schemas/processors/context.py +35 -0
  873. ciris_engine/schemas/processors/core.py +152 -0
  874. ciris_engine/schemas/processors/dma.py +105 -0
  875. ciris_engine/schemas/processors/error.py +122 -0
  876. ciris_engine/schemas/processors/main.py +109 -0
  877. ciris_engine/schemas/processors/phase_results.py +21 -0
  878. ciris_engine/schemas/processors/results.py +99 -0
  879. ciris_engine/schemas/processors/solitude.py +79 -0
  880. ciris_engine/schemas/processors/state.py +202 -0
  881. ciris_engine/schemas/processors/state_example.py +177 -0
  882. ciris_engine/schemas/processors/states.py +21 -0
  883. ciris_engine/schemas/processors/status.py +34 -0
  884. ciris_engine/schemas/registries/__init__.py +1 -0
  885. ciris_engine/schemas/registries/base.py +66 -0
  886. ciris_engine/schemas/resources/__init__.py +15 -0
  887. ciris_engine/schemas/resources/crisis.py +315 -0
  888. ciris_engine/schemas/runtime/__init__.py +42 -0
  889. ciris_engine/schemas/runtime/adapter_management.py +186 -0
  890. ciris_engine/schemas/runtime/api.py +58 -0
  891. ciris_engine/schemas/runtime/audit.py +50 -0
  892. ciris_engine/schemas/runtime/bootstrap.py +33 -0
  893. ciris_engine/schemas/runtime/contexts.py +61 -0
  894. ciris_engine/schemas/runtime/core.py +161 -0
  895. ciris_engine/schemas/runtime/enums.py +167 -0
  896. ciris_engine/schemas/runtime/extended.py +232 -0
  897. ciris_engine/schemas/runtime/manifest.py +311 -0
  898. ciris_engine/schemas/runtime/memory.py +60 -0
  899. ciris_engine/schemas/runtime/messages.py +108 -0
  900. ciris_engine/schemas/runtime/models.py +156 -0
  901. ciris_engine/schemas/runtime/processing_context.py +43 -0
  902. ciris_engine/schemas/runtime/protocols_core.py +96 -0
  903. ciris_engine/schemas/runtime/resources.py +33 -0
  904. ciris_engine/schemas/runtime/system_context.py +417 -0
  905. ciris_engine/schemas/secrets/__init__.py +1 -0
  906. ciris_engine/schemas/secrets/core.py +267 -0
  907. ciris_engine/schemas/secrets/service.py +95 -0
  908. ciris_engine/schemas/services/__init__.py +33 -0
  909. ciris_engine/schemas/services/audit_summary_node.py +172 -0
  910. ciris_engine/schemas/services/authority/__init__.py +39 -0
  911. ciris_engine/schemas/services/authority/jwt.py +158 -0
  912. ciris_engine/schemas/services/authority/wa_updates.py +138 -0
  913. ciris_engine/schemas/services/authority/wise_authority.py +163 -0
  914. ciris_engine/schemas/services/authority_core.py +370 -0
  915. ciris_engine/schemas/services/capabilities.py +72 -0
  916. ciris_engine/schemas/services/community_core.py +95 -0
  917. ciris_engine/schemas/services/context.py +111 -0
  918. ciris_engine/schemas/services/conversation_summary_node.py +189 -0
  919. ciris_engine/schemas/services/core/__init__.py +153 -0
  920. ciris_engine/schemas/services/core/runtime.py +262 -0
  921. ciris_engine/schemas/services/core/runtime_config.py +117 -0
  922. ciris_engine/schemas/services/core/secrets.py +65 -0
  923. ciris_engine/schemas/services/correlation_node.py +179 -0
  924. ciris_engine/schemas/services/credit_gate.py +92 -0
  925. ciris_engine/schemas/services/discord_nodes.py +299 -0
  926. ciris_engine/schemas/services/feedback_core.py +131 -0
  927. ciris_engine/schemas/services/filters_core.py +270 -0
  928. ciris_engine/schemas/services/governance.py +26 -0
  929. ciris_engine/schemas/services/graph/__init__.py +26 -0
  930. ciris_engine/schemas/services/graph/attributes.py +254 -0
  931. ciris_engine/schemas/services/graph/audit.py +98 -0
  932. ciris_engine/schemas/services/graph/consolidation.py +338 -0
  933. ciris_engine/schemas/services/graph/edge_types.py +43 -0
  934. ciris_engine/schemas/services/graph/edges.py +88 -0
  935. ciris_engine/schemas/services/graph/incident.py +312 -0
  936. ciris_engine/schemas/services/graph/memory.py +84 -0
  937. ciris_engine/schemas/services/graph/node_data.py +174 -0
  938. ciris_engine/schemas/services/graph/query_results.py +82 -0
  939. ciris_engine/schemas/services/graph/telemetry.py +250 -0
  940. ciris_engine/schemas/services/graph/tsdb_consolidation.py +27 -0
  941. ciris_engine/schemas/services/graph/tsdb_models.py +107 -0
  942. ciris_engine/schemas/services/graph_core.py +196 -0
  943. ciris_engine/schemas/services/graph_typed_nodes.py +194 -0
  944. ciris_engine/schemas/services/infrastructure/__init__.py +1 -0
  945. ciris_engine/schemas/services/infrastructure/resource_monitor.py +20 -0
  946. ciris_engine/schemas/services/lifecycle/__init__.py +9 -0
  947. ciris_engine/schemas/services/lifecycle/initialization.py +33 -0
  948. ciris_engine/schemas/services/lifecycle/time.py +50 -0
  949. ciris_engine/schemas/services/llm.py +187 -0
  950. ciris_engine/schemas/services/metadata.py +43 -0
  951. ciris_engine/schemas/services/nodes.py +704 -0
  952. ciris_engine/schemas/services/operations.py +126 -0
  953. ciris_engine/schemas/services/requests.py +128 -0
  954. ciris_engine/schemas/services/resources_core.py +182 -0
  955. ciris_engine/schemas/services/runtime_control.py +1010 -0
  956. ciris_engine/schemas/services/shutdown.py +88 -0
  957. ciris_engine/schemas/services/special/__init__.py +0 -0
  958. ciris_engine/schemas/services/special/self_observation.py +396 -0
  959. ciris_engine/schemas/services/trace_summary_node.py +199 -0
  960. ciris_engine/schemas/services/visibility.py +98 -0
  961. ciris_engine/schemas/streaming/__init__.py +10 -0
  962. ciris_engine/schemas/streaming/reasoning_stream.py +95 -0
  963. ciris_engine/schemas/telemetry/__init__.py +0 -0
  964. ciris_engine/schemas/telemetry/collector.py +67 -0
  965. ciris_engine/schemas/telemetry/core.py +252 -0
  966. ciris_engine/schemas/telemetry/unified.py +59 -0
  967. ciris_engine/schemas/tools.py +72 -0
  968. ciris_engine/schemas/types.py +47 -0
  969. ciris_engine/schemas/utils/__init__.py +1 -0
  970. ciris_engine/schemas/utils/config_validator.py +54 -0
  971. ciris_engine/utils/__init__.py +1 -0
  972. ciris_engine/utils/serialization.py +35 -0
  973. ciris_sdk/__init__.py +124 -0
  974. ciris_sdk/auth_store.py +261 -0
  975. ciris_sdk/client.py +261 -0
  976. ciris_sdk/exceptions.py +73 -0
  977. ciris_sdk/model_types.py +258 -0
  978. ciris_sdk/models.py +354 -0
  979. ciris_sdk/pagination.py +214 -0
  980. ciris_sdk/rate_limiter.py +188 -0
  981. ciris_sdk/setup.py +17 -0
  982. ciris_sdk/telemetry_models.py +257 -0
  983. ciris_sdk/telemetry_responses.py +199 -0
  984. ciris_sdk/transport.py +177 -0
  985. ciris_sdk/websocket.py +400 -0
  986. 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