aindy-runtime 1.1.0__tar.gz

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 (409) hide show
  1. aindy_runtime-1.1.0/AINDY/_version.py +1 -0
  2. aindy_runtime-1.1.0/AINDY/agents/__init__.py +1 -0
  3. aindy_runtime-1.1.0/AINDY/agents/agent_coordinator.py +464 -0
  4. aindy_runtime-1.1.0/AINDY/agents/agent_event_service.py +163 -0
  5. aindy_runtime-1.1.0/AINDY/agents/agent_message_bus.py +199 -0
  6. aindy_runtime-1.1.0/AINDY/agents/agent_runtime/__init__.py +83 -0
  7. aindy_runtime-1.1.0/AINDY/agents/agent_runtime/approvals.py +149 -0
  8. aindy_runtime-1.1.0/AINDY/agents/agent_runtime/creation.py +224 -0
  9. aindy_runtime-1.1.0/AINDY/agents/agent_runtime/execution.py +299 -0
  10. aindy_runtime-1.1.0/AINDY/agents/agent_runtime/planner_backends.py +205 -0
  11. aindy_runtime-1.1.0/AINDY/agents/agent_runtime/planning.py +232 -0
  12. aindy_runtime-1.1.0/AINDY/agents/agent_runtime/presentation.py +150 -0
  13. aindy_runtime-1.1.0/AINDY/agents/agent_runtime/replay.py +76 -0
  14. aindy_runtime-1.1.0/AINDY/agents/agent_runtime/shared.py +97 -0
  15. aindy_runtime-1.1.0/AINDY/agents/agent_runtime.py +7 -0
  16. aindy_runtime-1.1.0/AINDY/agents/agent_tools.py +26 -0
  17. aindy_runtime-1.1.0/AINDY/agents/autonomous_controller.py +219 -0
  18. aindy_runtime-1.1.0/AINDY/agents/capability_service.py +602 -0
  19. aindy_runtime-1.1.0/AINDY/agents/dead_letter_service.py +114 -0
  20. aindy_runtime-1.1.0/AINDY/agents/runtime_api.py +338 -0
  21. aindy_runtime-1.1.0/AINDY/agents/runtime_guardrails.py +293 -0
  22. aindy_runtime-1.1.0/AINDY/agents/stuck_run_service.py +397 -0
  23. aindy_runtime-1.1.0/AINDY/agents/stuck_run_watchdog.py +119 -0
  24. aindy_runtime-1.1.0/AINDY/agents/tool_registry.py +188 -0
  25. aindy_runtime-1.1.0/AINDY/agents/tool_syscalls.py +29 -0
  26. aindy_runtime-1.1.0/AINDY/apscheduler/__init__.py +1 -0
  27. aindy_runtime-1.1.0/AINDY/apscheduler/schedulers/__init__.py +1 -0
  28. aindy_runtime-1.1.0/AINDY/apscheduler/schedulers/background.py +51 -0
  29. aindy_runtime-1.1.0/AINDY/apscheduler/triggers/__init__.py +1 -0
  30. aindy_runtime-1.1.0/AINDY/apscheduler/triggers/cron.py +20 -0
  31. aindy_runtime-1.1.0/AINDY/apscheduler/triggers/interval.py +6 -0
  32. aindy_runtime-1.1.0/AINDY/auth/__init__.py +2 -0
  33. aindy_runtime-1.1.0/AINDY/auth/api_key_auth.py +22 -0
  34. aindy_runtime-1.1.0/AINDY/cli.py +605 -0
  35. aindy_runtime-1.1.0/AINDY/config.py +407 -0
  36. aindy_runtime-1.1.0/AINDY/core/__init__.py +1 -0
  37. aindy_runtime-1.1.0/AINDY/core/distributed_queue.py +1237 -0
  38. aindy_runtime-1.1.0/AINDY/core/execution_dispatcher.py +582 -0
  39. aindy_runtime-1.1.0/AINDY/core/execution_envelope.py +118 -0
  40. aindy_runtime-1.1.0/AINDY/core/execution_gate.py +572 -0
  41. aindy_runtime-1.1.0/AINDY/core/execution_guard.py +110 -0
  42. aindy_runtime-1.1.0/AINDY/core/execution_helper.py +81 -0
  43. aindy_runtime-1.1.0/AINDY/core/execution_pipeline/__init__.py +23 -0
  44. aindy_runtime-1.1.0/AINDY/core/execution_pipeline/context.py +98 -0
  45. aindy_runtime-1.1.0/AINDY/core/execution_pipeline/pipeline.py +358 -0
  46. aindy_runtime-1.1.0/AINDY/core/execution_pipeline/resources.py +163 -0
  47. aindy_runtime-1.1.0/AINDY/core/execution_pipeline/runtime_state.py +121 -0
  48. aindy_runtime-1.1.0/AINDY/core/execution_pipeline/shared.py +26 -0
  49. aindy_runtime-1.1.0/AINDY/core/execution_pipeline/signals.py +237 -0
  50. aindy_runtime-1.1.0/AINDY/core/execution_pipeline/waits.py +91 -0
  51. aindy_runtime-1.1.0/AINDY/core/execution_record_service.py +88 -0
  52. aindy_runtime-1.1.0/AINDY/core/execution_service.py +84 -0
  53. aindy_runtime-1.1.0/AINDY/core/execution_signal_helper.py +135 -0
  54. aindy_runtime-1.1.0/AINDY/core/execution_unit_service.py +476 -0
  55. aindy_runtime-1.1.0/AINDY/core/flow_run_rehydration.py +396 -0
  56. aindy_runtime-1.1.0/AINDY/core/observability_events.py +164 -0
  57. aindy_runtime-1.1.0/AINDY/core/request_metric_writer.py +155 -0
  58. aindy_runtime-1.1.0/AINDY/core/response_adapter.py +70 -0
  59. aindy_runtime-1.1.0/AINDY/core/resume_watchdog.py +134 -0
  60. aindy_runtime-1.1.0/AINDY/core/retry_policy.py +265 -0
  61. aindy_runtime-1.1.0/AINDY/core/route_execution_guard.py +249 -0
  62. aindy_runtime-1.1.0/AINDY/core/router_guard.py +223 -0
  63. aindy_runtime-1.1.0/AINDY/core/system_event_service.py +626 -0
  64. aindy_runtime-1.1.0/AINDY/core/system_event_types.py +55 -0
  65. aindy_runtime-1.1.0/AINDY/core/wait_condition.py +179 -0
  66. aindy_runtime-1.1.0/AINDY/core/wait_rehydration.py +309 -0
  67. aindy_runtime-1.1.0/AINDY/db/__init__.py +7 -0
  68. aindy_runtime-1.1.0/AINDY/db/base.py +5 -0
  69. aindy_runtime-1.1.0/AINDY/db/create_all.py +15 -0
  70. aindy_runtime-1.1.0/AINDY/db/dao/__init__.py +153 -0
  71. aindy_runtime-1.1.0/AINDY/db/dao/memory_node_dao.py +1716 -0
  72. aindy_runtime-1.1.0/AINDY/db/dao/memory_trace_dao.py +161 -0
  73. aindy_runtime-1.1.0/AINDY/db/database.py +192 -0
  74. aindy_runtime-1.1.0/AINDY/db/model_registry.py +73 -0
  75. aindy_runtime-1.1.0/AINDY/db/models/__init__.py +70 -0
  76. aindy_runtime-1.1.0/AINDY/db/models/agent.py +54 -0
  77. aindy_runtime-1.1.0/AINDY/db/models/agent_event.py +52 -0
  78. aindy_runtime-1.1.0/AINDY/db/models/agent_registry.py +23 -0
  79. aindy_runtime-1.1.0/AINDY/db/models/agent_run.py +137 -0
  80. aindy_runtime-1.1.0/AINDY/db/models/api_key.py +84 -0
  81. aindy_runtime-1.1.0/AINDY/db/models/background_task_lease.py +17 -0
  82. aindy_runtime-1.1.0/AINDY/db/models/capability.py +80 -0
  83. aindy_runtime-1.1.0/AINDY/db/models/dynamic_flow.py +55 -0
  84. aindy_runtime-1.1.0/AINDY/db/models/dynamic_node.py +56 -0
  85. aindy_runtime-1.1.0/AINDY/db/models/effect_record.py +89 -0
  86. aindy_runtime-1.1.0/AINDY/db/models/event_edge.py +46 -0
  87. aindy_runtime-1.1.0/AINDY/db/models/execution_unit.py +178 -0
  88. aindy_runtime-1.1.0/AINDY/db/models/flow_run.py +94 -0
  89. aindy_runtime-1.1.0/AINDY/db/models/job_log.py +45 -0
  90. aindy_runtime-1.1.0/AINDY/db/models/memory_metrics.py +20 -0
  91. aindy_runtime-1.1.0/AINDY/db/models/memory_node_history.py +44 -0
  92. aindy_runtime-1.1.0/AINDY/db/models/memory_trace.py +22 -0
  93. aindy_runtime-1.1.0/AINDY/db/models/memory_trace_node.py +22 -0
  94. aindy_runtime-1.1.0/AINDY/db/models/nodus_scheduled_job.py +74 -0
  95. aindy_runtime-1.1.0/AINDY/db/models/nodus_trace_event.py +74 -0
  96. aindy_runtime-1.1.0/AINDY/db/models/request_metric.py +20 -0
  97. aindy_runtime-1.1.0/AINDY/db/models/system_event.py +33 -0
  98. aindy_runtime-1.1.0/AINDY/db/models/system_health_log.py +13 -0
  99. aindy_runtime-1.1.0/AINDY/db/models/system_state_snapshot.py +23 -0
  100. aindy_runtime-1.1.0/AINDY/db/models/user.py +26 -0
  101. aindy_runtime-1.1.0/AINDY/db/models/user_identity.py +69 -0
  102. aindy_runtime-1.1.0/AINDY/db/models/waiting_flow_run.py +33 -0
  103. aindy_runtime-1.1.0/AINDY/db/models/webhook_subscription.py +51 -0
  104. aindy_runtime-1.1.0/AINDY/db/mongo_setup.py +179 -0
  105. aindy_runtime-1.1.0/AINDY/db/schema_contract.py +628 -0
  106. aindy_runtime-1.1.0/AINDY/db/schema_ops.py +110 -0
  107. aindy_runtime-1.1.0/AINDY/deepseek_config.json +27 -0
  108. aindy_runtime-1.1.0/AINDY/exception_handlers.py +208 -0
  109. aindy_runtime-1.1.0/AINDY/kernel/__init__.py +171 -0
  110. aindy_runtime-1.1.0/AINDY/kernel/circuit_breaker.py +177 -0
  111. aindy_runtime-1.1.0/AINDY/kernel/condition_codes.py +154 -0
  112. aindy_runtime-1.1.0/AINDY/kernel/errors.py +5 -0
  113. aindy_runtime-1.1.0/AINDY/kernel/event_bus.py +557 -0
  114. aindy_runtime-1.1.0/AINDY/kernel/redis_wait_registry.py +115 -0
  115. aindy_runtime-1.1.0/AINDY/kernel/resource_manager.py +911 -0
  116. aindy_runtime-1.1.0/AINDY/kernel/resume_spec.py +59 -0
  117. aindy_runtime-1.1.0/AINDY/kernel/scheduler/__init__.py +32 -0
  118. aindy_runtime-1.1.0/AINDY/kernel/scheduler/common.py +81 -0
  119. aindy_runtime-1.1.0/AINDY/kernel/scheduler/core.py +141 -0
  120. aindy_runtime-1.1.0/AINDY/kernel/scheduler/cross_instance.py +147 -0
  121. aindy_runtime-1.1.0/AINDY/kernel/scheduler/dispatch.py +85 -0
  122. aindy_runtime-1.1.0/AINDY/kernel/scheduler/engine.py +32 -0
  123. aindy_runtime-1.1.0/AINDY/kernel/scheduler/persistence.py +100 -0
  124. aindy_runtime-1.1.0/AINDY/kernel/scheduler/recovery.py +122 -0
  125. aindy_runtime-1.1.0/AINDY/kernel/scheduler/waits.py +211 -0
  126. aindy_runtime-1.1.0/AINDY/kernel/scheduler_engine.py +2 -0
  127. aindy_runtime-1.1.0/AINDY/kernel/syscall_dispatcher.py +902 -0
  128. aindy_runtime-1.1.0/AINDY/kernel/syscall_handlers.py +21 -0
  129. aindy_runtime-1.1.0/AINDY/kernel/syscall_registry.py +1313 -0
  130. aindy_runtime-1.1.0/AINDY/kernel/syscall_versioning.py +250 -0
  131. aindy_runtime-1.1.0/AINDY/kernel/tenant_context.py +171 -0
  132. aindy_runtime-1.1.0/AINDY/main.py +95 -0
  133. aindy_runtime-1.1.0/AINDY/memory/__init__.py +26 -0
  134. aindy_runtime-1.1.0/AINDY/memory/bridge.py +263 -0
  135. aindy_runtime-1.1.0/AINDY/memory/embedding_jobs.py +194 -0
  136. aindy_runtime-1.1.0/AINDY/memory/embedding_service.py +185 -0
  137. aindy_runtime-1.1.0/AINDY/memory/ingest_queue.py +190 -0
  138. aindy_runtime-1.1.0/AINDY/memory/memory_address_space.py +358 -0
  139. aindy_runtime-1.1.0/AINDY/memory/memory_capture_engine.py +562 -0
  140. aindy_runtime-1.1.0/AINDY/memory/memory_helpers.py +137 -0
  141. aindy_runtime-1.1.0/AINDY/memory/memory_ingest_service.py +221 -0
  142. aindy_runtime-1.1.0/AINDY/memory/memory_persistence.py +248 -0
  143. aindy_runtime-1.1.0/AINDY/memory/memory_scoring_service.py +181 -0
  144. aindy_runtime-1.1.0/AINDY/memory/nodus_memory_bridge.py +395 -0
  145. aindy_runtime-1.1.0/AINDY/middleware.py +185 -0
  146. aindy_runtime-1.1.0/AINDY/nodus/__init__.py +28 -0
  147. aindy_runtime-1.1.0/AINDY/nodus/runtime/__init__.py +1 -0
  148. aindy_runtime-1.1.0/AINDY/nodus/runtime/aindy_runtime.py +14 -0
  149. aindy_runtime-1.1.0/AINDY/nodus/runtime/embedding.py +4 -0
  150. aindy_runtime-1.1.0/AINDY/nodus/runtime/memory_bridge.py +265 -0
  151. aindy_runtime-1.1.0/AINDY/nodus/stdlib/.nodus/deps.json +8 -0
  152. aindy_runtime-1.1.0/AINDY/platform/dist/assets/AgentApprovalInbox-xp4dnTLc.js +1 -0
  153. aindy_runtime-1.1.0/AINDY/platform/dist/assets/AgentConsole-BwJhlQMZ.js +1 -0
  154. aindy_runtime-1.1.0/AINDY/platform/dist/assets/AgentRegistry-DipCGz5Q.js +1 -0
  155. aindy_runtime-1.1.0/AINDY/platform/dist/assets/ExecutionConsole-DviutjyX.js +1 -0
  156. aindy_runtime-1.1.0/AINDY/platform/dist/assets/FlowEngineConsole-DgNp6YSR.js +3 -0
  157. aindy_runtime-1.1.0/AINDY/platform/dist/assets/HealthDashboard-BipaBrfK.js +1 -0
  158. aindy_runtime-1.1.0/AINDY/platform/dist/assets/ObservabilityDashboard-dzZSTNIx.js +68 -0
  159. aindy_runtime-1.1.0/AINDY/platform/dist/assets/RippleTraceViewer-DmGwtwnz.js +1 -0
  160. aindy_runtime-1.1.0/AINDY/platform/dist/assets/SurfacePrimitives-ClHsSZxI.js +1 -0
  161. aindy_runtime-1.1.0/AINDY/platform/dist/assets/agent-BQJyJP8K.js +1 -0
  162. aindy_runtime-1.1.0/AINDY/platform/dist/assets/index-BljliAfI.css +1 -0
  163. aindy_runtime-1.1.0/AINDY/platform/dist/assets/index-CI4gqdMf.js +77 -0
  164. aindy_runtime-1.1.0/AINDY/platform/dist/assets/operator-DY3yPK_P.js +1 -0
  165. aindy_runtime-1.1.0/AINDY/platform/dist/index.html +13 -0
  166. aindy_runtime-1.1.0/AINDY/platform_layer/__init__.py +39 -0
  167. aindy_runtime-1.1.0/AINDY/platform_layer/agent_plugin_contracts.py +50 -0
  168. aindy_runtime-1.1.0/AINDY/platform_layer/api_key_service.py +162 -0
  169. aindy_runtime-1.1.0/AINDY/platform_layer/app_runtime.py +19 -0
  170. aindy_runtime-1.1.0/AINDY/platform_layer/async_execution_context.py +22 -0
  171. aindy_runtime-1.1.0/AINDY/platform_layer/async_job_service.py +1321 -0
  172. aindy_runtime-1.1.0/AINDY/platform_layer/bootstrap_contract.py +144 -0
  173. aindy_runtime-1.1.0/AINDY/platform_layer/bootstrap_graph.py +82 -0
  174. aindy_runtime-1.1.0/AINDY/platform_layer/cache_backend.py +23 -0
  175. aindy_runtime-1.1.0/AINDY/platform_layer/deepseek_client.py +228 -0
  176. aindy_runtime-1.1.0/AINDY/platform_layer/deployment_contract.py +1193 -0
  177. aindy_runtime-1.1.0/AINDY/platform_layer/domain_health.py +59 -0
  178. aindy_runtime-1.1.0/AINDY/platform_layer/event_service.py +712 -0
  179. aindy_runtime-1.1.0/AINDY/platform_layer/event_trace_service.py +291 -0
  180. aindy_runtime-1.1.0/AINDY/platform_layer/extension_abi.py +288 -0
  181. aindy_runtime-1.1.0/AINDY/platform_layer/extension_boundary.py +72 -0
  182. aindy_runtime-1.1.0/AINDY/platform_layer/extension_capabilities.py +225 -0
  183. aindy_runtime-1.1.0/AINDY/platform_layer/extension_execution_model.py +374 -0
  184. aindy_runtime-1.1.0/AINDY/platform_layer/extension_policy.py +255 -0
  185. aindy_runtime-1.1.0/AINDY/platform_layer/extension_provenance.py +418 -0
  186. aindy_runtime-1.1.0/AINDY/platform_layer/extension_provenance_inventory.py +99 -0
  187. aindy_runtime-1.1.0/AINDY/platform_layer/extension_runtime_api.py +180 -0
  188. aindy_runtime-1.1.0/AINDY/platform_layer/extension_runtime_inventory.py +180 -0
  189. aindy_runtime-1.1.0/AINDY/platform_layer/extension_worker.py +1299 -0
  190. aindy_runtime-1.1.0/AINDY/platform_layer/external_call_service.py +123 -0
  191. aindy_runtime-1.1.0/AINDY/platform_layer/health_service.py +924 -0
  192. aindy_runtime-1.1.0/AINDY/platform_layer/kernel_proc_reader.py +231 -0
  193. aindy_runtime-1.1.0/AINDY/platform_layer/llm_client.py +105 -0
  194. aindy_runtime-1.1.0/AINDY/platform_layer/log_config.py +127 -0
  195. aindy_runtime-1.1.0/AINDY/platform_layer/memory_runtime.py +69 -0
  196. aindy_runtime-1.1.0/AINDY/platform_layer/metrics.py +340 -0
  197. aindy_runtime-1.1.0/AINDY/platform_layer/node_registry.py +812 -0
  198. aindy_runtime-1.1.0/AINDY/platform_layer/nodus_script_store.py +92 -0
  199. aindy_runtime-1.1.0/AINDY/platform_layer/openai_client.py +319 -0
  200. aindy_runtime-1.1.0/AINDY/platform_layer/otel.py +98 -0
  201. aindy_runtime-1.1.0/AINDY/platform_layer/platform_loader.py +255 -0
  202. aindy_runtime-1.1.0/AINDY/platform_layer/plugin_artifacts.py +164 -0
  203. aindy_runtime-1.1.0/AINDY/platform_layer/plugin_host.py +1185 -0
  204. aindy_runtime-1.1.0/AINDY/platform_layer/public_contract.py +417 -0
  205. aindy_runtime-1.1.0/AINDY/platform_layer/rate_limiter.py +73 -0
  206. aindy_runtime-1.1.0/AINDY/platform_layer/recovery_jobs.py +279 -0
  207. aindy_runtime-1.1.0/AINDY/platform_layer/registry.py +1875 -0
  208. aindy_runtime-1.1.0/AINDY/platform_layer/registry_contracts.py +476 -0
  209. aindy_runtime-1.1.0/AINDY/platform_layer/response_adapters.py +98 -0
  210. aindy_runtime-1.1.0/AINDY/platform_layer/runtime_agent_defaults.py +211 -0
  211. aindy_runtime-1.1.0/AINDY/platform_layer/runtime_callback_host.py +97 -0
  212. aindy_runtime-1.1.0/AINDY/platform_layer/runtime_callback_worker.py +97 -0
  213. aindy_runtime-1.1.0/AINDY/platform_layer/runtime_compatibility.py +37 -0
  214. aindy_runtime-1.1.0/AINDY/platform_layer/sandbox_certification.py +920 -0
  215. aindy_runtime-1.1.0/AINDY/platform_layer/sandbox_runner.py +2437 -0
  216. aindy_runtime-1.1.0/AINDY/platform_layer/scheduler_service.py +807 -0
  217. aindy_runtime-1.1.0/AINDY/platform_layer/system_state_service.py +280 -0
  218. aindy_runtime-1.1.0/AINDY/platform_layer/trace_context.py +107 -0
  219. aindy_runtime-1.1.0/AINDY/platform_layer/user_ids.py +31 -0
  220. aindy_runtime-1.1.0/AINDY/platform_layer/watcher_contract.py +24 -0
  221. aindy_runtime-1.1.0/AINDY/platform_layer/watcher_service.py +80 -0
  222. aindy_runtime-1.1.0/AINDY/plugins/nodes/__init__.py +13 -0
  223. aindy_runtime-1.1.0/AINDY/routes/__init__.py +52 -0
  224. aindy_runtime-1.1.0/AINDY/routes/agent_router.py +366 -0
  225. aindy_runtime-1.1.0/AINDY/routes/auth_router.py +178 -0
  226. aindy_runtime-1.1.0/AINDY/routes/coordination_router.py +443 -0
  227. aindy_runtime-1.1.0/AINDY/routes/db_verify_router.py +35 -0
  228. aindy_runtime-1.1.0/AINDY/routes/flow_router.py +200 -0
  229. aindy_runtime-1.1.0/AINDY/routes/health_router.py +659 -0
  230. aindy_runtime-1.1.0/AINDY/routes/memory_metrics_router.py +101 -0
  231. aindy_runtime-1.1.0/AINDY/routes/memory_router.py +737 -0
  232. aindy_runtime-1.1.0/AINDY/routes/memory_trace_router.py +176 -0
  233. aindy_runtime-1.1.0/AINDY/routes/observability_router.py +416 -0
  234. aindy_runtime-1.1.0/AINDY/routes/platform/__init__.py +73 -0
  235. aindy_runtime-1.1.0/AINDY/routes/platform/admin_router.py +63 -0
  236. aindy_runtime-1.1.0/AINDY/routes/platform/flows_router.py +167 -0
  237. aindy_runtime-1.1.0/AINDY/routes/platform/keys_router.py +116 -0
  238. aindy_runtime-1.1.0/AINDY/routes/platform/nodes_router.py +105 -0
  239. aindy_runtime-1.1.0/AINDY/routes/platform/nodus_flow_router.py +84 -0
  240. aindy_runtime-1.1.0/AINDY/routes/platform/nodus_router.py +161 -0
  241. aindy_runtime-1.1.0/AINDY/routes/platform/nodus_schedule_router.py +97 -0
  242. aindy_runtime-1.1.0/AINDY/routes/platform/nodus_shared.py +151 -0
  243. aindy_runtime-1.1.0/AINDY/routes/platform/platform_ops_router.py +257 -0
  244. aindy_runtime-1.1.0/AINDY/routes/platform/queue_router.py +134 -0
  245. aindy_runtime-1.1.0/AINDY/routes/platform/schemas.py +146 -0
  246. aindy_runtime-1.1.0/AINDY/routes/platform/webhooks_router.py +108 -0
  247. aindy_runtime-1.1.0/AINDY/routes/platform_router.py +121 -0
  248. aindy_runtime-1.1.0/AINDY/routes/version_router.py +92 -0
  249. aindy_runtime-1.1.0/AINDY/routes/watcher_router.py +208 -0
  250. aindy_runtime-1.1.0/AINDY/routing.py +80 -0
  251. aindy_runtime-1.1.0/AINDY/runtime/__init__.py +227 -0
  252. aindy_runtime-1.1.0/AINDY/runtime/execution_loop.py +1 -0
  253. aindy_runtime-1.1.0/AINDY/runtime/execution_registry.py +37 -0
  254. aindy_runtime-1.1.0/AINDY/runtime/flow_definitions.py +26 -0
  255. aindy_runtime-1.1.0/AINDY/runtime/flow_definitions_engine.py +181 -0
  256. aindy_runtime-1.1.0/AINDY/runtime/flow_definitions_extended.py +86 -0
  257. aindy_runtime-1.1.0/AINDY/runtime/flow_definitions_memory.py +462 -0
  258. aindy_runtime-1.1.0/AINDY/runtime/flow_definitions_observability.py +204 -0
  259. aindy_runtime-1.1.0/AINDY/runtime/flow_engine/__init__.py +53 -0
  260. aindy_runtime-1.1.0/AINDY/runtime/flow_engine/entrypoints.py +167 -0
  261. aindy_runtime-1.1.0/AINDY/runtime/flow_engine/event_router.py +94 -0
  262. aindy_runtime-1.1.0/AINDY/runtime/flow_engine/node_executor.py +60 -0
  263. aindy_runtime-1.1.0/AINDY/runtime/flow_engine/registry.py +38 -0
  264. aindy_runtime-1.1.0/AINDY/runtime/flow_engine/runner.py +396 -0
  265. aindy_runtime-1.1.0/AINDY/runtime/flow_engine/runner_completion.py +204 -0
  266. aindy_runtime-1.1.0/AINDY/runtime/flow_engine/runner_failure.py +106 -0
  267. aindy_runtime-1.1.0/AINDY/runtime/flow_engine/runner_steps.py +370 -0
  268. aindy_runtime-1.1.0/AINDY/runtime/flow_engine/serialization.py +173 -0
  269. aindy_runtime-1.1.0/AINDY/runtime/flow_engine/shared.py +37 -0
  270. aindy_runtime-1.1.0/AINDY/runtime/flow_helpers.py +20 -0
  271. aindy_runtime-1.1.0/AINDY/runtime/flow_registry.py +319 -0
  272. aindy_runtime-1.1.0/AINDY/runtime/memory/__init__.py +19 -0
  273. aindy_runtime-1.1.0/AINDY/runtime/memory/context_builder.py +35 -0
  274. aindy_runtime-1.1.0/AINDY/runtime/memory/filters.py +62 -0
  275. aindy_runtime-1.1.0/AINDY/runtime/memory/memory_feedback.py +64 -0
  276. aindy_runtime-1.1.0/AINDY/runtime/memory/memory_learning.py +126 -0
  277. aindy_runtime-1.1.0/AINDY/runtime/memory/memory_metrics.py +151 -0
  278. aindy_runtime-1.1.0/AINDY/runtime/memory/metrics_store.py +143 -0
  279. aindy_runtime-1.1.0/AINDY/runtime/memory/native_scorer.py +166 -0
  280. aindy_runtime-1.1.0/AINDY/runtime/memory/orchestrator.py +194 -0
  281. aindy_runtime-1.1.0/AINDY/runtime/memory/query_expander.py +19 -0
  282. aindy_runtime-1.1.0/AINDY/runtime/memory/scorer.py +162 -0
  283. aindy_runtime-1.1.0/AINDY/runtime/memory/strategies.py +51 -0
  284. aindy_runtime-1.1.0/AINDY/runtime/memory/types.py +61 -0
  285. aindy_runtime-1.1.0/AINDY/runtime/memory_loop.py +228 -0
  286. aindy_runtime-1.1.0/AINDY/runtime/nodus_adapter.py +1002 -0
  287. aindy_runtime-1.1.0/AINDY/runtime/nodus_builtins.py +530 -0
  288. aindy_runtime-1.1.0/AINDY/runtime/nodus_execution_service.py +707 -0
  289. aindy_runtime-1.1.0/AINDY/runtime/nodus_flow_compiler.py +269 -0
  290. aindy_runtime-1.1.0/AINDY/runtime/nodus_runtime_adapter.py +459 -0
  291. aindy_runtime-1.1.0/AINDY/runtime/nodus_schedule_service.py +478 -0
  292. aindy_runtime-1.1.0/AINDY/runtime/nodus_security.py +180 -0
  293. aindy_runtime-1.1.0/AINDY/runtime/nodus_trace_service.py +151 -0
  294. aindy_runtime-1.1.0/AINDY/runtime/nodus_worker.py +272 -0
  295. aindy_runtime-1.1.0/AINDY/runtime_only.py +325 -0
  296. aindy_runtime-1.1.0/AINDY/runtime_plugins.json +10 -0
  297. aindy_runtime-1.1.0/AINDY/schemas/__init__.py +2 -0
  298. aindy_runtime-1.1.0/AINDY/schemas/auth_schemas.py +17 -0
  299. aindy_runtime-1.1.0/AINDY/services/auth_service.py +489 -0
  300. aindy_runtime-1.1.0/AINDY/spa_fallback.py +153 -0
  301. aindy_runtime-1.1.0/AINDY/startup.py +1542 -0
  302. aindy_runtime-1.1.0/AINDY/system_manifest.json +22 -0
  303. aindy_runtime-1.1.0/AINDY/utils/__init__.py +36 -0
  304. aindy_runtime-1.1.0/AINDY/utils/normalize_encoding.py +18 -0
  305. aindy_runtime-1.1.0/AINDY/utils/sanitize_text.py +41 -0
  306. aindy_runtime-1.1.0/AINDY/utils/text_constraints.py +66 -0
  307. aindy_runtime-1.1.0/AINDY/utils/uuid_utils.py +17 -0
  308. aindy_runtime-1.1.0/AINDY/version.json +6 -0
  309. aindy_runtime-1.1.0/AINDY/watcher/__init__.py +5 -0
  310. aindy_runtime-1.1.0/AINDY/watcher/constants.py +33 -0
  311. aindy_runtime-1.1.0/AINDY/worker/__init__.py +112 -0
  312. aindy_runtime-1.1.0/AINDY/worker/__main__.py +85 -0
  313. aindy_runtime-1.1.0/AINDY/worker/health_server.py +221 -0
  314. aindy_runtime-1.1.0/AINDY/worker/memory_ingest_worker.py +60 -0
  315. aindy_runtime-1.1.0/AINDY/worker/metric_writer_worker.py +58 -0
  316. aindy_runtime-1.1.0/AINDY/worker/worker_loop.py +897 -0
  317. aindy_runtime-1.1.0/AINDY/worker.py +106 -0
  318. aindy_runtime-1.1.0/LICENSE +21 -0
  319. aindy_runtime-1.1.0/MANIFEST.in +3 -0
  320. aindy_runtime-1.1.0/PKG-INFO +539 -0
  321. aindy_runtime-1.1.0/README.md +436 -0
  322. aindy_runtime-1.1.0/aindy_runtime.egg-info/PKG-INFO +539 -0
  323. aindy_runtime-1.1.0/aindy_runtime.egg-info/SOURCES.txt +407 -0
  324. aindy_runtime-1.1.0/aindy_runtime.egg-info/dependency_links.txt +1 -0
  325. aindy_runtime-1.1.0/aindy_runtime.egg-info/entry_points.txt +2 -0
  326. aindy_runtime-1.1.0/aindy_runtime.egg-info/requires.txt +82 -0
  327. aindy_runtime-1.1.0/aindy_runtime.egg-info/top_level.txt +1 -0
  328. aindy_runtime-1.1.0/docs/runtime/AGENT_RUNTIME.md +370 -0
  329. aindy_runtime-1.1.0/docs/runtime/ARCHITECTURE.md +147 -0
  330. aindy_runtime-1.1.0/docs/runtime/ARCHITECTURE_RISK.md +155 -0
  331. aindy_runtime-1.1.0/docs/runtime/AUTH_SYSTEM_AUDIT.md +178 -0
  332. aindy_runtime-1.1.0/docs/runtime/CHANGE_IMPACT_MATRIX.md +263 -0
  333. aindy_runtime-1.1.0/docs/runtime/CI_OWNERSHIP.md +125 -0
  334. aindy_runtime-1.1.0/docs/runtime/CONDITION_CODES.md +219 -0
  335. aindy_runtime-1.1.0/docs/runtime/CROSS_REPO_COMPATIBILITY.md +176 -0
  336. aindy_runtime-1.1.0/docs/runtime/DB_OWNERSHIP_CONTRACT.md +201 -0
  337. aindy_runtime-1.1.0/docs/runtime/DECISION_LOG.md +301 -0
  338. aindy_runtime-1.1.0/docs/runtime/DEGRADED_MODE_MATRIX.md +293 -0
  339. aindy_runtime-1.1.0/docs/runtime/DEGRADED_RUNTIME_MODES.md +54 -0
  340. aindy_runtime-1.1.0/docs/runtime/DEPENDENCY_CRITICALITY_MATRIX.md +261 -0
  341. aindy_runtime-1.1.0/docs/runtime/DEPLOYMENT_PROFILES.md +101 -0
  342. aindy_runtime-1.1.0/docs/runtime/DEPLOYMENT_TARGETS.md +112 -0
  343. aindy_runtime-1.1.0/docs/runtime/DOCSET_CHANGELOG.md +22 -0
  344. aindy_runtime-1.1.0/docs/runtime/EXECUTION_AUDIT.md +243 -0
  345. aindy_runtime-1.1.0/docs/runtime/EXECUTION_CONTRACT.md +626 -0
  346. aindy_runtime-1.1.0/docs/runtime/EXECUTION_INVARIANTS.md +577 -0
  347. aindy_runtime-1.1.0/docs/runtime/EXTENSION_ABI.md +42 -0
  348. aindy_runtime-1.1.0/docs/runtime/EXTENSION_CAPABILITIES.md +92 -0
  349. aindy_runtime-1.1.0/docs/runtime/EXTENSION_PROVENANCE.md +84 -0
  350. aindy_runtime-1.1.0/docs/runtime/EXTENSION_TRUST_MODEL.md +205 -0
  351. aindy_runtime-1.1.0/docs/runtime/FOUNDATIONAL_PATTERN.md +328 -0
  352. aindy_runtime-1.1.0/docs/runtime/GITHUB_SETTINGS_CHECKLIST.md +100 -0
  353. aindy_runtime-1.1.0/docs/runtime/HIGH_CONFLICT_DOC_RECONCILIATION_PLAN.md +259 -0
  354. aindy_runtime-1.1.0/docs/runtime/IDEMPOTENCY_CONTRACT.md +427 -0
  355. aindy_runtime-1.1.0/docs/runtime/INCIDENT_CLASSIFICATION.md +259 -0
  356. aindy_runtime-1.1.0/docs/runtime/INFINITY_LOOP_AUDIT.md +395 -0
  357. aindy_runtime-1.1.0/docs/runtime/INVARIANT_TEST_MAPPING.md +221 -0
  358. aindy_runtime-1.1.0/docs/runtime/KERNEL_CAPABILITY_AUDIT.md +355 -0
  359. aindy_runtime-1.1.0/docs/runtime/LOCAL_AND_CLOUD_AUDIT.md +392 -0
  360. aindy_runtime-1.1.0/docs/runtime/MACOS_CONTAINER_POLICY.md +121 -0
  361. aindy_runtime-1.1.0/docs/runtime/MEMORY_ADDRESS_SPACE.md +248 -0
  362. aindy_runtime-1.1.0/docs/runtime/MEMORY_BRIDGE.md +460 -0
  363. aindy_runtime-1.1.0/docs/runtime/MEMORY_BRIDGE_CONTRACT.md +394 -0
  364. aindy_runtime-1.1.0/docs/runtime/MONETIZATION_AUDIT.md +306 -0
  365. aindy_runtime-1.1.0/docs/runtime/NATIVE_MEMORY_BRIDGE.md +405 -0
  366. aindy_runtime-1.1.0/docs/runtime/NODUS_DEVELOPER_GUIDE.md +337 -0
  367. aindy_runtime-1.1.0/docs/runtime/OPEN_QUESTIONS.md +254 -0
  368. aindy_runtime-1.1.0/docs/runtime/OPERATOR_RUNBOOK.md +422 -0
  369. aindy_runtime-1.1.0/docs/runtime/OS_ISOLATION_LAYER.md +297 -0
  370. aindy_runtime-1.1.0/docs/runtime/PLATFORM_PURITY_AUDIT.md +239 -0
  371. aindy_runtime-1.1.0/docs/runtime/PLATFORM_READINESS_AUDIT.md +182 -0
  372. aindy_runtime-1.1.0/docs/runtime/PROFILE_SUPPORT_MATRIX.md +304 -0
  373. aindy_runtime-1.1.0/docs/runtime/PUBLIC_API_CONTRACT.md +173 -0
  374. aindy_runtime-1.1.0/docs/runtime/PUBLIC_RUNTIME_SURFACES.md +234 -0
  375. aindy_runtime-1.1.0/docs/runtime/QUICKSTART.md +184 -0
  376. aindy_runtime-1.1.0/docs/runtime/REAL_USER_REALITY_AUDIT.md +41 -0
  377. aindy_runtime-1.1.0/docs/runtime/RELEASE_CHECKLIST.md +251 -0
  378. aindy_runtime-1.1.0/docs/runtime/RELEASE_GATES.md +218 -0
  379. aindy_runtime-1.1.0/docs/runtime/RELEASE_STAGING.md +79 -0
  380. aindy_runtime-1.1.0/docs/runtime/REPO_COMPATIBILITY_POLICY.md +117 -0
  381. aindy_runtime-1.1.0/docs/runtime/RETRY_POLICY.md +225 -0
  382. aindy_runtime-1.1.0/docs/runtime/ROUTE_OWNERSHIP_INVENTORY.md +238 -0
  383. aindy_runtime-1.1.0/docs/runtime/RUNTIME_BEHAVIOR.md +210 -0
  384. aindy_runtime-1.1.0/docs/runtime/RUNTIME_BOUNDARY.md +370 -0
  385. aindy_runtime-1.1.0/docs/runtime/RUNTIME_DOCSET_BOUNDARY.md +95 -0
  386. aindy_runtime-1.1.0/docs/runtime/RUNTIME_DOCSET_GOVERNANCE.md +242 -0
  387. aindy_runtime-1.1.0/docs/runtime/RUNTIME_DOCSET_STATUS_AUDIT.md +283 -0
  388. aindy_runtime-1.1.0/docs/runtime/RUNTIME_DOC_ALIGNMENT_AUDIT.md +437 -0
  389. aindy_runtime-1.1.0/docs/runtime/RUNTIME_DOC_INDEX.md +206 -0
  390. aindy_runtime-1.1.0/docs/runtime/RUNTIME_MODULE_MAP.md +522 -0
  391. aindy_runtime-1.1.0/docs/runtime/RUNTIME_ONLY_DEPLOYMENT.md +274 -0
  392. aindy_runtime-1.1.0/docs/runtime/RUNTIME_STABILITY_INDEX.md +305 -0
  393. aindy_runtime-1.1.0/docs/runtime/SANDBOX_ESCAPE_AUDIT.md +266 -0
  394. aindy_runtime-1.1.0/docs/runtime/SCHEMA_LIFECYCLE.md +184 -0
  395. aindy_runtime-1.1.0/docs/runtime/SDK_CONTRACT.md +157 -0
  396. aindy_runtime-1.1.0/docs/runtime/SECURITY_MATRIX.md +247 -0
  397. aindy_runtime-1.1.0/docs/runtime/SECURITY_POLICY.md +95 -0
  398. aindy_runtime-1.1.0/docs/runtime/SECURITY_POSTURE.md +295 -0
  399. aindy_runtime-1.1.0/docs/runtime/SYSCALL_REFERENCE.md +362 -0
  400. aindy_runtime-1.1.0/docs/runtime/SYSCALL_SYSTEM.md +528 -0
  401. aindy_runtime-1.1.0/docs/runtime/SYSTEM_CAPABILITY_AUDIT.md +61 -0
  402. aindy_runtime-1.1.0/docs/runtime/SYSTEM_INTEGRITY_AUDIT.md +215 -0
  403. aindy_runtime-1.1.0/docs/runtime/SYSTEM_LIMIT_LEVERAGE_AUDIT.md +49 -0
  404. aindy_runtime-1.1.0/docs/runtime/TEST_GAP_BACKLOG.md +285 -0
  405. aindy_runtime-1.1.0/docs/runtime/TEST_GAP_WORK_ITEMS.md +224 -0
  406. aindy_runtime-1.1.0/docs/runtime/TEST_STRATEGY.md +322 -0
  407. aindy_runtime-1.1.0/docs/runtime/UI_CONTRACT.md +123 -0
  408. aindy_runtime-1.1.0/pyproject.toml +136 -0
  409. aindy_runtime-1.1.0/setup.cfg +4 -0
@@ -0,0 +1 @@
1
+ __version__ = "1.1.0"
@@ -0,0 +1 @@
1
+ # agents -- AINDY agentic execution layer
@@ -0,0 +1,464 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime, timedelta, timezone
4
+ from typing import Any
5
+
6
+ from AINDY.db.models.agent_registry import AgentRegistry
7
+ from AINDY.db.models.system_event import SystemEvent
8
+ from AINDY.agents.agent_message_bus import publish_operation_request
9
+ from AINDY.agents.runtime_guardrails import AgentRuntimeGuardrailViolation, enforce_delegation_guardrails
10
+ from AINDY.platform_layer.registry import get_agent_ranking_strategy
11
+ from AINDY.utils.uuid_utils import normalize_uuid
12
+
13
+
14
+ STALE_AGENT_MINUTES = 10
15
+
16
+
17
+ def register_or_update_agent(
18
+ db,
19
+ *,
20
+ agent_id: str,
21
+ capabilities: list[str] | None = None,
22
+ current_state: dict[str, Any] | None = None,
23
+ load: float = 0.0,
24
+ health_status: str = "healthy",
25
+ ) -> dict[str, Any]:
26
+ normalized_agent_id = normalize_uuid(agent_id)
27
+ row = db.query(AgentRegistry).filter(AgentRegistry.agent_id == normalized_agent_id).first()
28
+ if row is None:
29
+ row = AgentRegistry(agent_id=normalized_agent_id)
30
+ db.add(row)
31
+ row.capabilities = capabilities or row.capabilities or []
32
+ row.current_state = current_state or row.current_state or {}
33
+ row.load = max(0.0, min(1.0, float(load or 0.0)))
34
+ row.health_status = health_status or "healthy"
35
+ row.last_seen = datetime.now(timezone.utc)
36
+ db.commit()
37
+ db.refresh(row)
38
+ return serialize_agent_registry(row)
39
+
40
+
41
+ def list_agents(db, *, include_stale: bool = False) -> list[dict[str, Any]]:
42
+ query = db.query(AgentRegistry).order_by(AgentRegistry.last_seen.desc())
43
+ rows = query.all()
44
+ now = datetime.now(timezone.utc)
45
+ results = []
46
+ for row in rows:
47
+ serialized = serialize_agent_registry(row)
48
+ serialized["stale"] = _is_stale(row.last_seen, now)
49
+ if include_stale or not serialized["stale"]:
50
+ results.append(serialized)
51
+ return results
52
+
53
+
54
+ def get_agent_status(db) -> dict[str, Any]:
55
+ agents = list_agents(db, include_stale=True)
56
+ healthy = sum(1 for agent in agents if agent["health_status"] == "healthy" and not agent["stale"])
57
+ degraded = sum(1 for agent in agents if agent["health_status"] == "degraded" and not agent["stale"])
58
+ critical = sum(1 for agent in agents if agent["health_status"] == "critical" or agent["stale"])
59
+ return {
60
+ "total_agents": len(agents),
61
+ "healthy_agents": healthy,
62
+ "degraded_agents": degraded,
63
+ "critical_agents": critical,
64
+ "agents": agents,
65
+ }
66
+
67
+
68
+ def assign_operation(
69
+ db,
70
+ operation: dict[str, Any],
71
+ *,
72
+ user_id: str | None = None,
73
+ trace_id: str | None = None,
74
+ sender_agent_id: str | None = None,
75
+ ) -> dict[str, Any] | None:
76
+ candidates = _rank_candidate_agents(db, operation, user_id=user_id)
77
+ if not candidates:
78
+ return None
79
+ best = candidates[0]
80
+ if sender_agent_id:
81
+ publish_operation_request(
82
+ db=db,
83
+ sender_agent_id=sender_agent_id,
84
+ recipient_agent_id=best["agent_id"],
85
+ operation=operation,
86
+ user_id=user_id,
87
+ trace_id=trace_id,
88
+ )
89
+ return best
90
+
91
+
92
+ def broadcast_operation(
93
+ db,
94
+ operation: dict[str, Any],
95
+ *,
96
+ user_id: str | None = None,
97
+ trace_id: str | None = None,
98
+ sender_agent_id: str | None = None,
99
+ limit: int = 5,
100
+ ) -> list[dict[str, Any]]:
101
+ ranked = _rank_candidate_agents(db, operation, user_id=user_id)[:limit]
102
+ if sender_agent_id:
103
+ for candidate in ranked:
104
+ publish_operation_request(
105
+ db=db,
106
+ sender_agent_id=sender_agent_id,
107
+ recipient_agent_id=candidate["agent_id"],
108
+ operation=operation,
109
+ user_id=user_id,
110
+ trace_id=trace_id,
111
+ )
112
+ return ranked
113
+
114
+
115
+ def decide_execution_mode(
116
+ db,
117
+ *,
118
+ local_agent_id: str | None,
119
+ operation: dict[str, Any],
120
+ user_id: str | None = None,
121
+ ) -> dict[str, Any]:
122
+ ranked = _rank_candidate_agents(db, operation, user_id=user_id)
123
+ if not ranked:
124
+ return {"mode": "local", "selected_agent": None, "candidates": []}
125
+
126
+ best = resolve_conflict(ranked)
127
+ if local_agent_id and str(best["agent_id"]) == str(local_agent_id):
128
+ return {"mode": "local", "selected_agent": best, "candidates": ranked[:3]}
129
+ if len(ranked) >= 2 and abs(ranked[0]["coordination_score"] - ranked[1]["coordination_score"]) <= 0.05:
130
+ return {"mode": "collaborate", "selected_agent": best, "candidates": ranked[:3]}
131
+ return {"mode": "delegate", "selected_agent": best, "candidates": ranked[:3]}
132
+
133
+
134
+ def coordination_graph(db, *, user_id: str | None = None, limit: int = 100) -> dict[str, Any]:
135
+ query = (
136
+ db.query(SystemEvent)
137
+ .filter(SystemEvent.agent_id.isnot(None))
138
+ .order_by(SystemEvent.timestamp.desc())
139
+ .limit(limit)
140
+ )
141
+ if user_id:
142
+ query = query.filter(SystemEvent.user_id == normalize_uuid(user_id))
143
+ rows = query.all()
144
+ nodes = {}
145
+ edges = []
146
+ for row in rows:
147
+ agent_key = str(row.agent_id)
148
+ nodes[agent_key] = {
149
+ "id": agent_key,
150
+ "health_status": None,
151
+ "load": None,
152
+ }
153
+ payload = row.payload or {}
154
+ recipient = payload.get("recipient_agent_id")
155
+ if recipient:
156
+ edges.append(
157
+ {
158
+ "source": agent_key,
159
+ "target": str(recipient),
160
+ "event_type": row.type,
161
+ "trace_id": row.trace_id,
162
+ "timestamp": row.timestamp.isoformat() if row.timestamp else None,
163
+ }
164
+ )
165
+ for agent in list_agents(db, include_stale=True):
166
+ nodes[str(agent["agent_id"])] = {
167
+ "id": str(agent["agent_id"]),
168
+ "health_status": agent["health_status"],
169
+ "load": agent["load"],
170
+ }
171
+ return {"nodes": list(nodes.values()), "edges": edges}
172
+
173
+
174
+ def _rank_candidate_agents(db, operation: dict[str, Any], *, user_id: str | None = None) -> list[dict[str, Any]]:
175
+ operation_capabilities = set(operation.get("required_capabilities") or operation.get("capabilities") or [])
176
+ candidates = [
177
+ _enrich_candidate_for_coordination(db, row, operation_capabilities=operation_capabilities, user_id=user_id)
178
+ for row in list_agents(db, include_stale=False)
179
+ ]
180
+ context = {
181
+ "db": db,
182
+ "operation": operation,
183
+ "user_id": user_id,
184
+ "required_capabilities": sorted(operation_capabilities),
185
+ }
186
+
187
+ ranking_strategy = get_agent_ranking_strategy()
188
+ if ranking_strategy is not None:
189
+ ranked = ranking_strategy(candidates, context)
190
+ if isinstance(ranked, list):
191
+ return ranked
192
+
193
+ ranked = list(candidates)
194
+ ranked.sort(key=lambda item: item["coordination_score"], reverse=True)
195
+ return ranked
196
+
197
+
198
+ def _enrich_candidate_for_coordination(
199
+ db,
200
+ row: dict[str, Any],
201
+ *,
202
+ operation_capabilities: set[str],
203
+ user_id: str | None = None,
204
+ ) -> dict[str, Any]:
205
+ capability_overlap = 0.0
206
+ capabilities = set(row.get("capabilities") or [])
207
+ if operation_capabilities:
208
+ capability_overlap = len(operation_capabilities & capabilities) / max(1, len(operation_capabilities))
209
+ elif capabilities:
210
+ capability_overlap = 0.5
211
+
212
+ past_performance = _agent_performance_score(db, row["agent_id"], user_id=user_id)
213
+ score = (
214
+ capability_overlap * 0.45
215
+ + (1.0 - float(row.get("load") or 0.0)) * 0.20
216
+ + past_performance * 0.20
217
+ + (0.15 if row.get("health_status") == "healthy" else 0.05 if row.get("health_status") == "degraded" else 0.0)
218
+ )
219
+ enriched = dict(row)
220
+ enriched["coordination_score"] = round(max(0.0, min(1.0, score)), 4)
221
+ enriched["capability_overlap"] = round(capability_overlap, 4)
222
+ enriched["past_performance"] = round(past_performance, 4)
223
+ return enriched
224
+
225
+
226
+ def resolve_conflict(candidates: list[dict[str, Any]]) -> dict[str, Any]:
227
+ if not candidates:
228
+ raise ValueError("resolve_conflict requires at least one candidate")
229
+ if len(candidates) == 1:
230
+ return candidates[0]
231
+
232
+ top_score = float(candidates[0].get("coordination_score") or 0.0)
233
+ tied = [
234
+ candidate for candidate in candidates
235
+ if abs(float(candidate.get("coordination_score") or 0.0) - top_score) <= 0.05
236
+ ]
237
+ tied.sort(
238
+ key=lambda item: (
239
+ -(float(item.get("capability_overlap") or 0.0)),
240
+ float(item.get("load") or 1.0),
241
+ -(float(item.get("past_performance") or 0.0)),
242
+ )
243
+ )
244
+ return tied[0]
245
+
246
+
247
+ def _agent_performance_score(db, agent_id: str, *, user_id: str | None = None) -> float:
248
+ query = db.query(SystemEvent).filter(SystemEvent.agent_id == normalize_uuid(agent_id))
249
+ if user_id:
250
+ query = query.filter(SystemEvent.user_id == normalize_uuid(user_id))
251
+ rows = query.order_by(SystemEvent.timestamp.desc()).limit(50).all()
252
+ if not rows:
253
+ return 0.5
254
+ successes = sum(1 for row in rows if row.type.endswith(".completed") or row.type == "execution.completed")
255
+ failures = sum(1 for row in rows if row.type.endswith(".failed") or row.type.startswith("error."))
256
+ total = max(1, successes + failures)
257
+ return max(0.1, min(1.0, (successes + 0.5) / (total + 1.0)))
258
+
259
+
260
+ def _is_stale(last_seen: datetime | None, now: datetime) -> bool:
261
+ if not last_seen:
262
+ return True
263
+ if last_seen.tzinfo is None:
264
+ last_seen = last_seen.replace(tzinfo=timezone.utc)
265
+ return last_seen < now - timedelta(minutes=STALE_AGENT_MINUTES)
266
+
267
+
268
+ def serialize_agent_registry(row: AgentRegistry) -> dict[str, Any]:
269
+ return {
270
+ "agent_id": str(row.agent_id),
271
+ "capabilities": row.capabilities or [],
272
+ "current_state": row.current_state or {},
273
+ "load": float(row.load or 0.0),
274
+ "health_status": row.health_status,
275
+ "last_seen": row.last_seen.isoformat() if row.last_seen else None,
276
+ }
277
+
278
+
279
+ def dispatch_delegated_run(
280
+ db,
281
+ *,
282
+ parent_run,
283
+ selected_agent: dict,
284
+ delegation_mode: str,
285
+ user_id: str,
286
+ trace_id: str | None = None,
287
+ ) -> dict[str, Any] | None:
288
+ try:
289
+ import uuid as _uuid
290
+
291
+ from AINDY.agents.agent_runtime.shared import _OBJECTIVE_ATTR, _run_objective
292
+ from AINDY.agents.agent_runtime.shared import LOCAL_AGENT_ID
293
+ from AINDY.agents.capability_service import mint_token
294
+ from AINDY.db.models import AgentRun
295
+
296
+ objective = _run_objective(parent_run)
297
+ if not objective or getattr(parent_run, "user_id", None) is None:
298
+ return None
299
+
300
+ enforce_delegation_guardrails(
301
+ db,
302
+ parent_run=parent_run,
303
+ selected_agent_id=selected_agent.get("agent_id"),
304
+ trace_id=trace_id or parent_run.trace_id,
305
+ )
306
+ child_run_id = _uuid.uuid4()
307
+ child_correlation_id = f"run_{_uuid.uuid4()}"
308
+ selected_agent_id = normalize_uuid(selected_agent.get("agent_id"))
309
+
310
+ child_run = AgentRun(
311
+ id=child_run_id,
312
+ user_id=parent_run.user_id,
313
+ agent_type=str(selected_agent.get("agent_id", "default"))[:64],
314
+ plan=parent_run.plan,
315
+ executive_summary=parent_run.executive_summary,
316
+ overall_risk=parent_run.overall_risk or "high",
317
+ status="approved",
318
+ steps_total=parent_run.steps_total,
319
+ correlation_id=child_correlation_id,
320
+ trace_id=trace_id or parent_run.trace_id,
321
+ parent_run_id=parent_run.id,
322
+ spawned_by_agent_id=selected_agent_id,
323
+ coordination_role=delegation_mode,
324
+ )
325
+ setattr(child_run, _OBJECTIVE_ATTR, objective)
326
+ db.add(child_run)
327
+ db.flush()
328
+
329
+ child_token = mint_token(
330
+ run_id=str(child_run_id),
331
+ user_id=str(parent_run.user_id),
332
+ plan=child_run.plan,
333
+ db=db,
334
+ approval_mode="manual",
335
+ agent_type=getattr(parent_run, "agent_type", "default") or "default",
336
+ )
337
+ if child_token:
338
+ child_run.capability_token = child_token
339
+ child_run.execution_token = child_token.get("execution_token")
340
+
341
+ parent_run.status = "delegated"
342
+ parent_run.completed_at = None
343
+ db.flush()
344
+ db.refresh(child_run)
345
+
346
+ assign_operation(
347
+ db,
348
+ operation={
349
+ "name": objective,
350
+ "description": parent_run.executive_summary or objective,
351
+ "request": objective,
352
+ "required_capabilities": list(
353
+ (child_token or {}).get("allowed_capabilities") or []
354
+ ),
355
+ "child_run_id": str(child_run.id),
356
+ "parent_run_id": str(parent_run.id),
357
+ },
358
+ user_id=user_id,
359
+ trace_id=trace_id or parent_run.trace_id,
360
+ sender_agent_id=str(getattr(parent_run, "spawned_by_agent_id", None) or LOCAL_AGENT_ID),
361
+ )
362
+ return _serialize_delegated_run(child_run)
363
+ except AgentRuntimeGuardrailViolation:
364
+ raise
365
+ except Exception as exc:
366
+ import logging as _logging
367
+
368
+ _logging.getLogger(__name__).warning(
369
+ "[AgentCoordinator] dispatch_delegated_run failed: %s", exc
370
+ )
371
+ return None
372
+
373
+
374
+ def _serialize_delegated_run(run) -> dict[str, Any]:
375
+ return {
376
+ "run_id": str(run.id),
377
+ "parent_run_id": str(run.parent_run_id) if run.parent_run_id else None,
378
+ "spawned_by_agent_id": str(run.spawned_by_agent_id) if run.spawned_by_agent_id else None,
379
+ "status": run.status,
380
+ "coordination_role": run.coordination_role,
381
+ "correlation_id": run.correlation_id,
382
+ }
383
+
384
+
385
+ def detect_run_conflict(
386
+ db,
387
+ *,
388
+ user_id: str,
389
+ objective: str,
390
+ agent_id: str | None = None,
391
+ ) -> dict[str, Any]:
392
+ from AINDY.agents.agent_runtime.shared import _run_objective
393
+ from AINDY.db.models import AgentRun
394
+
395
+ uid = normalize_uuid(user_id)
396
+ active_runs = (
397
+ db.query(AgentRun)
398
+ .filter(
399
+ AgentRun.user_id == uid,
400
+ AgentRun.status.in_(["approved", "executing", "delegated"]),
401
+ )
402
+ .order_by(AgentRun.created_at.desc())
403
+ .limit(20)
404
+ .all()
405
+ )
406
+ normalized_objective = str(objective or "").strip().lower()
407
+ for run in active_runs:
408
+ run_obj = str(_run_objective(run) or "").strip().lower()
409
+ if run_obj == normalized_objective:
410
+ if agent_id and getattr(run, "correlation_id", None) == agent_id:
411
+ continue
412
+ return {
413
+ "conflict": True,
414
+ "conflicting_run_id": str(run.id),
415
+ "conflicting_status": run.status,
416
+ }
417
+ return {
418
+ "conflict": False,
419
+ "conflicting_run_id": None,
420
+ "conflicting_status": None,
421
+ }
422
+
423
+
424
+ def detect_memory_write_conflict(
425
+ db,
426
+ *,
427
+ user_id: str,
428
+ memory_path: str,
429
+ agent_id: str | None = None,
430
+ ) -> dict[str, Any]:
431
+ uid = normalize_uuid(user_id)
432
+ window = datetime.now(timezone.utc) - timedelta(seconds=30)
433
+ recent = (
434
+ db.query(SystemEvent)
435
+ .filter(
436
+ SystemEvent.user_id == uid,
437
+ SystemEvent.type == "agent.message.memory_share",
438
+ SystemEvent.timestamp >= window,
439
+ )
440
+ .order_by(SystemEvent.timestamp.desc())
441
+ .limit(10)
442
+ .all()
443
+ )
444
+ for event in recent:
445
+ payload = event.payload or {}
446
+ if payload.get("memory_path") == memory_path:
447
+ conflicting_agent = str(event.agent_id) if event.agent_id else None
448
+ if agent_id and conflicting_agent == agent_id:
449
+ continue
450
+ return {
451
+ "conflict": True,
452
+ "conflicting_agent_id": conflicting_agent,
453
+ "message": (
454
+ f"Memory path '{memory_path}' was written by agent "
455
+ f"{conflicting_agent} within the last 30 seconds."
456
+ ),
457
+ }
458
+ return {
459
+ "conflict": False,
460
+ "conflicting_agent_id": None,
461
+ "message": "No conflict detected.",
462
+ }
463
+
464
+
@@ -0,0 +1,163 @@
1
+ """
2
+ AgentEventService — thin helper for emitting lifecycle events (Sprint N+8).
3
+
4
+ emit_event() is the single entry point for agent lifecycle persistence.
5
+ Critical execution paths pass required=True so missing audit events fail closed.
6
+
7
+ Usage:
8
+ from AINDY.agents.agent_event_service import emit_event
9
+ emit_event(
10
+ run_id=str(run.id),
11
+ user_id=run.user_id,
12
+ correlation_id=run.correlation_id,
13
+ event_type="PLAN_CREATED",
14
+ payload={"overall_risk": "low", "steps_total": 3},
15
+ db=db,
16
+ )
17
+ """
18
+ import logging
19
+ import uuid
20
+ from datetime import datetime, timezone
21
+ from typing import Optional
22
+
23
+ from sqlalchemy.orm import Session
24
+
25
+ from AINDY.core.execution_signal_helper import queue_system_event
26
+ from AINDY.core.system_event_service import SystemEventEmissionError
27
+ from AINDY.platform_layer.trace_context import get_parent_event_id
28
+ from AINDY.platform_layer.trace_context import get_trace_id
29
+ from AINDY.utils.uuid_utils import normalize_uuid
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+ AGENT_EVENT_TYPES = {
34
+ "PLAN_CREATED",
35
+ "APPROVED",
36
+ "REJECTED",
37
+ "EXECUTION_STARTED",
38
+ "COMPLETED",
39
+ "EXECUTION_FAILED",
40
+ "CAPABILITY_DENIED",
41
+ "RECOVERED",
42
+ "REPLAY_CREATED",
43
+ }
44
+
45
+
46
+ def emit_event(
47
+ run_id: str,
48
+ user_id: str,
49
+ event_type: str,
50
+ db: Session,
51
+ correlation_id: Optional[str] = None,
52
+ payload: Optional[dict] = None,
53
+ required: bool = False,
54
+ ) -> str | None:
55
+ """
56
+ Persist one AgentEvent lifecycle row.
57
+
58
+ Raises when required=True and either the AgentEvent row or matching
59
+ SystemEvent cannot be persisted.
60
+
61
+ Args:
62
+ run_id: UUID string of the AgentRun
63
+ user_id: Owner user ID
64
+ event_type: One of AGENT_EVENT_TYPES (PLAN_CREATED, APPROVED, etc.)
65
+ db: SQLAlchemy session
66
+ correlation_id: Optional run_<uuid4> token (None for pre-N+8 runs)
67
+ payload: Optional dict of event-specific data
68
+ """
69
+ try:
70
+ from AINDY.db.models import AgentEvent
71
+
72
+ if event_type not in AGENT_EVENT_TYPES:
73
+ logger.warning(
74
+ "[AgentEventService] Unknown event type %s for run %s",
75
+ event_type,
76
+ run_id,
77
+ )
78
+
79
+ parsed_run_id = run_id
80
+ if isinstance(run_id, str):
81
+ try:
82
+ parsed_run_id = uuid.UUID(run_id)
83
+ except ValueError:
84
+ parsed_run_id = run_id
85
+
86
+ normalized_user_id = normalize_uuid(user_id) if user_id is not None else None
87
+
88
+ system_event_id = queue_system_event(
89
+ db=db,
90
+ event_type=f"agent.{str(event_type).lower()}",
91
+ user_id=user_id,
92
+ trace_id=get_trace_id() or correlation_id or run_id,
93
+ parent_event_id=get_parent_event_id(),
94
+ source="agent",
95
+ payload={
96
+ "run_id": run_id,
97
+ "correlation_id": correlation_id,
98
+ "event_type": event_type,
99
+ **(payload or {}),
100
+ },
101
+ required=required,
102
+ )
103
+
104
+ normalized_system_event_id = None
105
+ if system_event_id:
106
+ try:
107
+ candidate = uuid.UUID(str(system_event_id))
108
+ from AINDY.db.models.system_event import SystemEvent
109
+
110
+ exists = (
111
+ db.query(SystemEvent.id)
112
+ .filter(SystemEvent.id == candidate)
113
+ .first()
114
+ )
115
+ if exists:
116
+ normalized_system_event_id = normalize_uuid(candidate)
117
+ else:
118
+ logger.warning(
119
+ "[AgentEventService] SystemEvent %s missing; linking skipped for %s",
120
+ system_event_id,
121
+ event_type,
122
+ )
123
+ except Exception:
124
+ logger.warning(
125
+ "[AgentEventService] Invalid SystemEvent %s for %s",
126
+ system_event_id,
127
+ event_type,
128
+ )
129
+
130
+ event = AgentEvent(
131
+ id=uuid.uuid4(),
132
+ run_id=parsed_run_id,
133
+ correlation_id=correlation_id,
134
+ user_id=normalized_user_id,
135
+ event_type=event_type,
136
+ payload=payload or {},
137
+ system_event_id=normalized_system_event_id,
138
+ occurred_at=datetime.now(timezone.utc),
139
+ )
140
+ db.add(event)
141
+ db.commit()
142
+
143
+ logger.debug(
144
+ "[AgentEventService] Emitted %s for run %s (correlation=%s)",
145
+ event_type,
146
+ run_id,
147
+ correlation_id,
148
+ )
149
+ return str(system_event_id) if system_event_id else None
150
+
151
+ except Exception as exc:
152
+ logger.warning(
153
+ "[AgentEventService] Failed to emit %s for run %s: %s",
154
+ event_type,
155
+ run_id,
156
+ exc,
157
+ )
158
+ if required:
159
+ raise SystemEventEmissionError(
160
+ f"Required agent event '{event_type}' failed for run {run_id}"
161
+ ) from exc
162
+ return None
163
+