@team-agent/installer 0.2.11 → 0.3.0

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 (326) hide show
  1. package/Cargo.lock +744 -0
  2. package/Cargo.toml +34 -0
  3. package/crates/team-agent/Cargo.toml +33 -0
  4. package/crates/team-agent/src/cli/adapters.rs +1343 -0
  5. package/crates/team-agent/src/cli/diagnose.rs +554 -0
  6. package/crates/team-agent/src/cli/emit.rs +1077 -0
  7. package/crates/team-agent/src/cli/helpers.rs +88 -0
  8. package/crates/team-agent/src/cli/leader.rs +216 -0
  9. package/crates/team-agent/src/cli/mod.rs +1141 -0
  10. package/crates/team-agent/src/cli/profile.rs +306 -0
  11. package/crates/team-agent/src/cli/send.rs +215 -0
  12. package/crates/team-agent/src/cli/status.rs +179 -0
  13. package/crates/team-agent/src/cli/status_port.rs +502 -0
  14. package/crates/team-agent/src/cli/tests/base.rs +616 -0
  15. package/crates/team-agent/src/cli/tests/compile.rs +96 -0
  16. package/crates/team-agent/src/cli/tests/divergence.rs +509 -0
  17. package/crates/team-agent/src/cli/tests/lane_c.rs +333 -0
  18. package/crates/team-agent/src/cli/tests/leader_watch.rs +395 -0
  19. package/crates/team-agent/src/cli/tests/main_preserved.rs +675 -0
  20. package/crates/team-agent/src/cli/tests/missing_subcommands.rs +390 -0
  21. package/crates/team-agent/src/cli/tests/mod.rs +97 -0
  22. package/crates/team-agent/src/cli/tests/peer_allow.rs +137 -0
  23. package/crates/team-agent/src/cli/tests/repair_state_byte_lock.rs +302 -0
  24. package/crates/team-agent/src/cli/tests/run_delegation.rs +305 -0
  25. package/crates/team-agent/src/cli/tests/status_send.rs +385 -0
  26. package/crates/team-agent/src/cli/tests/verb_profile.rs +182 -0
  27. package/crates/team-agent/src/cli/tests/verb_settle.rs +236 -0
  28. package/crates/team-agent/src/cli/tests/verb_validate.rs +184 -0
  29. package/crates/team-agent/src/cli/types.rs +605 -0
  30. package/crates/team-agent/src/compiler/tests.rs +701 -0
  31. package/crates/team-agent/src/compiler.rs +489 -0
  32. package/crates/team-agent/src/coordinator/backoff.rs +153 -0
  33. package/crates/team-agent/src/coordinator/health.rs +436 -0
  34. package/crates/team-agent/src/coordinator/mod.rs +80 -0
  35. package/crates/team-agent/src/coordinator/orphan.rs +179 -0
  36. package/crates/team-agent/src/coordinator/tests/abnormal.rs +255 -0
  37. package/crates/team-agent/src/coordinator/tests/basics.rs +262 -0
  38. package/crates/team-agent/src/coordinator/tests/daemon.rs +323 -0
  39. package/crates/team-agent/src/coordinator/tests/health_sync.rs +263 -0
  40. package/crates/team-agent/src/coordinator/tests/main_preserved.rs +136 -0
  41. package/crates/team-agent/src/coordinator/tests/mod.rs +310 -0
  42. package/crates/team-agent/src/coordinator/tests/spine.rs +261 -0
  43. package/crates/team-agent/src/coordinator/tests/takeover.rs +227 -0
  44. package/crates/team-agent/src/coordinator/tests/tick_core.rs +256 -0
  45. package/crates/team-agent/src/coordinator/tests/watch.rs +167 -0
  46. package/crates/team-agent/src/coordinator/tick.rs +2032 -0
  47. package/crates/team-agent/src/coordinator/types.rs +584 -0
  48. package/crates/team-agent/src/db/migration.rs +716 -0
  49. package/crates/team-agent/src/db/mod.rs +23 -0
  50. package/crates/team-agent/src/db/schema.rs +378 -0
  51. package/crates/team-agent/src/event_log.rs +375 -0
  52. package/crates/team-agent/src/fake_worker.rs +253 -0
  53. package/crates/team-agent/src/leader/helpers.rs +190 -0
  54. package/crates/team-agent/src/leader/inject.rs +33 -0
  55. package/crates/team-agent/src/leader/lease.rs +1063 -0
  56. package/crates/team-agent/src/leader/mod.rs +99 -0
  57. package/crates/team-agent/src/leader/owner_bind.rs +292 -0
  58. package/crates/team-agent/src/leader/rediscover/tests.rs +525 -0
  59. package/crates/team-agent/src/leader/rediscover.rs +1099 -0
  60. package/crates/team-agent/src/leader/start.rs +273 -0
  61. package/crates/team-agent/src/leader/takeover.rs +235 -0
  62. package/crates/team-agent/src/leader/tests/basics.rs +183 -0
  63. package/crates/team-agent/src/leader/tests/byte_findings.rs +234 -0
  64. package/crates/team-agent/src/leader/tests/identity.rs +206 -0
  65. package/crates/team-agent/src/leader/tests/idle.rs +271 -0
  66. package/crates/team-agent/src/leader/tests/lease_api.rs +225 -0
  67. package/crates/team-agent/src/leader/tests/lease_claim.rs +253 -0
  68. package/crates/team-agent/src/leader/tests/mod.rs +125 -0
  69. package/crates/team-agent/src/leader/tests/rediscover.rs +351 -0
  70. package/crates/team-agent/src/leader/tests/wake_start_owner.rs +204 -0
  71. package/crates/team-agent/src/leader/types.rs +487 -0
  72. package/crates/team-agent/src/lib.rs +85 -0
  73. package/crates/team-agent/src/lifecycle/display.rs +228 -0
  74. package/crates/team-agent/src/lifecycle/helpers.rs +112 -0
  75. package/crates/team-agent/src/lifecycle/launch/plan.rs +227 -0
  76. package/crates/team-agent/src/lifecycle/launch.rs +1833 -0
  77. package/crates/team-agent/src/lifecycle/mod.rs +62 -0
  78. package/crates/team-agent/src/lifecycle/restart/agent.rs +533 -0
  79. package/crates/team-agent/src/lifecycle/restart/common.rs +517 -0
  80. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +41 -0
  81. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +268 -0
  82. package/crates/team-agent/src/lifecycle/restart/remove.rs +780 -0
  83. package/crates/team-agent/src/lifecycle/restart/selection.rs +208 -0
  84. package/crates/team-agent/src/lifecycle/restart/team_state.rs +242 -0
  85. package/crates/team-agent/src/lifecycle/restart.rs +76 -0
  86. package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +455 -0
  87. package/crates/team-agent/src/lifecycle/tests/core.rs +989 -0
  88. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +583 -0
  89. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +933 -0
  90. package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +265 -0
  91. package/crates/team-agent/src/lifecycle/tests.rs +27 -0
  92. package/crates/team-agent/src/lifecycle/types.rs +685 -0
  93. package/crates/team-agent/src/main.rs +41 -0
  94. package/crates/team-agent/src/mcp_server/helpers.rs +228 -0
  95. package/crates/team-agent/src/mcp_server/mod.rs +183 -0
  96. package/crates/team-agent/src/mcp_server/normalize.rs +312 -0
  97. package/crates/team-agent/src/mcp_server/tests/golden.rs +283 -0
  98. package/crates/team-agent/src/mcp_server/tests/normalize.rs +244 -0
  99. package/crates/team-agent/src/mcp_server/tests/scoped.rs +189 -0
  100. package/crates/team-agent/src/mcp_server/tests/send.rs +222 -0
  101. package/crates/team-agent/src/mcp_server/tests/tools.rs +158 -0
  102. package/crates/team-agent/src/mcp_server/tests/wire.rs +159 -0
  103. package/crates/team-agent/src/mcp_server/tests.rs +38 -0
  104. package/crates/team-agent/src/mcp_server/tools.rs +603 -0
  105. package/crates/team-agent/src/mcp_server/types.rs +421 -0
  106. package/crates/team-agent/src/mcp_server/wire.rs +388 -0
  107. package/crates/team-agent/src/message_store.rs +767 -0
  108. package/crates/team-agent/src/messaging/activity.rs +433 -0
  109. package/crates/team-agent/src/messaging/delivery.rs +542 -0
  110. package/crates/team-agent/src/messaging/helpers.rs +209 -0
  111. package/crates/team-agent/src/messaging/leader_receiver.rs +340 -0
  112. package/crates/team-agent/src/messaging/mod.rs +147 -0
  113. package/crates/team-agent/src/messaging/peers.rs +32 -0
  114. package/crates/team-agent/src/messaging/results.rs +537 -0
  115. package/crates/team-agent/src/messaging/scheduler.rs +344 -0
  116. package/crates/team-agent/src/messaging/selftest.rs +100 -0
  117. package/crates/team-agent/src/messaging/send.rs +582 -0
  118. package/crates/team-agent/src/messaging/tests/basic.rs +357 -0
  119. package/crates/team-agent/src/messaging/tests/main_preserved.rs +122 -0
  120. package/crates/team-agent/src/messaging/tests/mod.rs +293 -0
  121. package/crates/team-agent/src/messaging/tests/runtime.rs +1422 -0
  122. package/crates/team-agent/src/messaging/tests/spine.rs +437 -0
  123. package/crates/team-agent/src/messaging/trust.rs +192 -0
  124. package/crates/team-agent/src/messaging/types.rs +355 -0
  125. package/crates/team-agent/src/messaging/watchers.rs +591 -0
  126. package/crates/team-agent/src/model/enums.rs +311 -0
  127. package/crates/team-agent/src/model/errors.rs +17 -0
  128. package/crates/team-agent/src/model/ids.rs +155 -0
  129. package/crates/team-agent/src/model/mod.rs +22 -0
  130. package/crates/team-agent/src/model/paths.rs +228 -0
  131. package/crates/team-agent/src/model/permissions.rs +567 -0
  132. package/crates/team-agent/src/model/routing.rs +340 -0
  133. package/crates/team-agent/src/model/spec.rs +680 -0
  134. package/crates/team-agent/src/model/task_graph.rs +380 -0
  135. package/crates/team-agent/src/model/testdata/fuzz.golden.yaml +43 -0
  136. package/crates/team-agent/src/model/testdata/fuzz.yaml +43 -0
  137. package/crates/team-agent/src/model/testdata/spec_invalid_a.yaml +207 -0
  138. package/crates/team-agent/src/model/testdata/team.spec.golden.yaml +206 -0
  139. package/crates/team-agent/src/model/testdata/team.spec.yaml +206 -0
  140. package/crates/team-agent/src/model/yaml/tests.rs +288 -0
  141. package/crates/team-agent/src/model/yaml.rs +800 -0
  142. package/crates/team-agent/src/packaging/install.rs +305 -0
  143. package/crates/team-agent/src/packaging/migrate.rs +30 -0
  144. package/crates/team-agent/src/packaging/mod.rs +82 -0
  145. package/crates/team-agent/src/packaging/repair.rs +24 -0
  146. package/crates/team-agent/src/packaging/tests.rs +829 -0
  147. package/crates/team-agent/src/packaging/types.rs +369 -0
  148. package/crates/team-agent/src/provider/adapter.rs +801 -0
  149. package/crates/team-agent/src/provider/approvals/mod.rs +2 -0
  150. package/crates/team-agent/src/provider/approvals/parsing.rs +452 -0
  151. package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +163 -0
  152. package/crates/team-agent/src/provider/classify.rs +456 -0
  153. package/crates/team-agent/src/provider/faults.rs +136 -0
  154. package/crates/team-agent/src/provider/helpers.rs +41 -0
  155. package/crates/team-agent/src/provider/mod.rs +53 -0
  156. package/crates/team-agent/src/provider/startup_prompt.rs +423 -0
  157. package/crates/team-agent/src/provider/tests/adapter.rs +239 -0
  158. package/crates/team-agent/src/provider/tests/classify.rs +240 -0
  159. package/crates/team-agent/src/provider/tests/faults.rs +120 -0
  160. package/crates/team-agent/src/provider/tests/idle.rs +208 -0
  161. package/crates/team-agent/src/provider/tests/wire.rs +213 -0
  162. package/crates/team-agent/src/provider/tests.rs +31 -0
  163. package/crates/team-agent/src/provider/types.rs +424 -0
  164. package/crates/team-agent/src/state/identity.rs +656 -0
  165. package/crates/team-agent/src/state/mod.rs +58 -0
  166. package/crates/team-agent/src/state/owner_gate.rs +423 -0
  167. package/crates/team-agent/src/state/persist.rs +712 -0
  168. package/crates/team-agent/src/state/projection.rs +657 -0
  169. package/crates/team-agent/src/state/selector.rs +105 -0
  170. package/crates/team-agent/src/state/testdata/state-rich.canonical.json +133 -0
  171. package/crates/team-agent/src/tmux_backend/tests.rs +586 -0
  172. package/crates/team-agent/src/tmux_backend.rs +758 -0
  173. package/crates/team-agent/src/transport/test_support.rs +252 -0
  174. package/crates/team-agent/src/transport/tests/behavior.rs +327 -0
  175. package/crates/team-agent/src/transport/tests/mod.rs +199 -0
  176. package/crates/team-agent/src/transport/tests/wire.rs +527 -0
  177. package/crates/team-agent/src/transport.rs +774 -0
  178. package/npm/install.mjs +90 -106
  179. package/package.json +15 -13
  180. package/crates/team-agent-core/Cargo.toml +0 -12
  181. package/crates/team-agent-core/src/lib.rs +0 -332
  182. package/crates/team-agent-core/src/main.rs +0 -152
  183. package/pyproject.toml +0 -18
  184. package/scripts/install.py +0 -88
  185. package/scripts/run_regression_tests.py +0 -83
  186. package/src/team_agent/__init__.py +0 -3
  187. package/src/team_agent/__main__.py +0 -5
  188. package/src/team_agent/_legacy_pane_discovery.py +0 -186
  189. package/src/team_agent/abnormal_track.py +0 -253
  190. package/src/team_agent/approvals/__init__.py +0 -65
  191. package/src/team_agent/approvals/constants.py +0 -6
  192. package/src/team_agent/approvals/parsing.py +0 -176
  193. package/src/team_agent/approvals/runtime_prompts.py +0 -171
  194. package/src/team_agent/approvals/status.py +0 -176
  195. package/src/team_agent/cli/__init__.py +0 -137
  196. package/src/team_agent/cli/commands.py +0 -481
  197. package/src/team_agent/cli/e2e.py +0 -202
  198. package/src/team_agent/cli/helpers.py +0 -226
  199. package/src/team_agent/cli/parser.py +0 -540
  200. package/src/team_agent/compiler.py +0 -334
  201. package/src/team_agent/coordinator/__init__.py +0 -53
  202. package/src/team_agent/coordinator/__main__.py +0 -119
  203. package/src/team_agent/coordinator/lifecycle.py +0 -411
  204. package/src/team_agent/coordinator/metadata.py +0 -61
  205. package/src/team_agent/coordinator/paths.py +0 -17
  206. package/src/team_agent/diagnose/__init__.py +0 -48
  207. package/src/team_agent/diagnose/checks.py +0 -101
  208. package/src/team_agent/diagnose/comms.py +0 -213
  209. package/src/team_agent/diagnose/health.py +0 -241
  210. package/src/team_agent/diagnose/orphan_cleanup.py +0 -364
  211. package/src/team_agent/diagnose/preflight.py +0 -194
  212. package/src/team_agent/diagnose/quick_start.py +0 -324
  213. package/src/team_agent/display/__init__.py +0 -92
  214. package/src/team_agent/display/adaptive.py +0 -511
  215. package/src/team_agent/display/backend.py +0 -46
  216. package/src/team_agent/display/close.py +0 -154
  217. package/src/team_agent/display/ghostty.py +0 -77
  218. package/src/team_agent/display/rebuild.py +0 -102
  219. package/src/team_agent/display/tiling.py +0 -156
  220. package/src/team_agent/display/worker_window.py +0 -114
  221. package/src/team_agent/display/workspace.py +0 -382
  222. package/src/team_agent/errors.py +0 -10
  223. package/src/team_agent/events.py +0 -84
  224. package/src/team_agent/fake_worker.py +0 -80
  225. package/src/team_agent/idle_predicate.py +0 -218
  226. package/src/team_agent/idle_takeover.py +0 -59
  227. package/src/team_agent/idle_takeover_wiring.py +0 -114
  228. package/src/team_agent/launch/__init__.py +0 -41
  229. package/src/team_agent/launch/bootstrap.py +0 -85
  230. package/src/team_agent/launch/config.py +0 -106
  231. package/src/team_agent/launch/core.py +0 -301
  232. package/src/team_agent/launch/requirements.py +0 -57
  233. package/src/team_agent/leader/__init__.py +0 -926
  234. package/src/team_agent/leader_binding.py +0 -183
  235. package/src/team_agent/lifecycle/__init__.py +0 -5
  236. package/src/team_agent/lifecycle/agents.py +0 -278
  237. package/src/team_agent/lifecycle/operations.py +0 -411
  238. package/src/team_agent/lifecycle/paste_buffer_hygiene.py +0 -39
  239. package/src/team_agent/lifecycle/start.py +0 -363
  240. package/src/team_agent/mcp_server/__init__.py +0 -42
  241. package/src/team_agent/mcp_server/__main__.py +0 -7
  242. package/src/team_agent/mcp_server/contracts.py +0 -148
  243. package/src/team_agent/mcp_server/normalize.py +0 -257
  244. package/src/team_agent/mcp_server/server.py +0 -150
  245. package/src/team_agent/mcp_server/tools.py +0 -352
  246. package/src/team_agent/message_store/__init__.py +0 -23
  247. package/src/team_agent/message_store/agent_health.py +0 -113
  248. package/src/team_agent/message_store/core.py +0 -497
  249. package/src/team_agent/message_store/leader_notification_log.py +0 -198
  250. package/src/team_agent/message_store/result_watchers.py +0 -251
  251. package/src/team_agent/message_store/schema.py +0 -308
  252. package/src/team_agent/message_store/schema_migration.py +0 -448
  253. package/src/team_agent/messaging/__init__.py +0 -1
  254. package/src/team_agent/messaging/activity_detector.py +0 -262
  255. package/src/team_agent/messaging/delivery.py +0 -504
  256. package/src/team_agent/messaging/deps.py +0 -247
  257. package/src/team_agent/messaging/idle_alerts.py +0 -423
  258. package/src/team_agent/messaging/internal_delivery.py +0 -46
  259. package/src/team_agent/messaging/leader.py +0 -497
  260. package/src/team_agent/messaging/leader_api_errors.py +0 -216
  261. package/src/team_agent/messaging/leader_panes.py +0 -673
  262. package/src/team_agent/messaging/owner_bypass.py +0 -29
  263. package/src/team_agent/messaging/result_delivery.py +0 -539
  264. package/src/team_agent/messaging/results.py +0 -447
  265. package/src/team_agent/messaging/scheduler.py +0 -450
  266. package/src/team_agent/messaging/send.py +0 -532
  267. package/src/team_agent/messaging/session_drift.py +0 -94
  268. package/src/team_agent/messaging/tmux_io.py +0 -506
  269. package/src/team_agent/messaging/tmux_prompt.py +0 -338
  270. package/src/team_agent/messaging/trust_auto_answer.py +0 -52
  271. package/src/team_agent/orchestrator/__init__.py +0 -376
  272. package/src/team_agent/orchestrator/plan.py +0 -122
  273. package/src/team_agent/orchestrator/state.py +0 -128
  274. package/src/team_agent/paths.py +0 -45
  275. package/src/team_agent/permissions.py +0 -123
  276. package/src/team_agent/profiles/__init__.py +0 -82
  277. package/src/team_agent/profiles/constants.py +0 -19
  278. package/src/team_agent/profiles/core.py +0 -407
  279. package/src/team_agent/profiles/helpers.py +0 -69
  280. package/src/team_agent/profiles/provider_env.py +0 -188
  281. package/src/team_agent/profiles/smoke.py +0 -201
  282. package/src/team_agent/provider_cli/__init__.py +0 -43
  283. package/src/team_agent/provider_cli/adapter.py +0 -172
  284. package/src/team_agent/provider_cli/base.py +0 -48
  285. package/src/team_agent/provider_cli/claude.py +0 -503
  286. package/src/team_agent/provider_cli/codex.py +0 -336
  287. package/src/team_agent/provider_cli/copilot.py +0 -8
  288. package/src/team_agent/provider_cli/fake.py +0 -39
  289. package/src/team_agent/provider_cli/gemini.py +0 -95
  290. package/src/team_agent/provider_cli/opencode.py +0 -8
  291. package/src/team_agent/provider_cli/prompt.py +0 -62
  292. package/src/team_agent/provider_cli/registry.py +0 -18
  293. package/src/team_agent/provider_cli/unsupported.py +0 -32
  294. package/src/team_agent/provider_state/README.md +0 -78
  295. package/src/team_agent/provider_state/__init__.py +0 -91
  296. package/src/team_agent/provider_state/claude.py +0 -86
  297. package/src/team_agent/provider_state/codex.py +0 -84
  298. package/src/team_agent/provider_state/common.py +0 -207
  299. package/src/team_agent/provider_state/registry.py +0 -118
  300. package/src/team_agent/providers.py +0 -163
  301. package/src/team_agent/quality_gates.py +0 -104
  302. package/src/team_agent/restart/__init__.py +0 -34
  303. package/src/team_agent/restart/orchestration.py +0 -554
  304. package/src/team_agent/restart/selection.py +0 -89
  305. package/src/team_agent/restart/snapshot.py +0 -70
  306. package/src/team_agent/routing.py +0 -84
  307. package/src/team_agent/runtime.py +0 -1243
  308. package/src/team_agent/rust_core.py +0 -327
  309. package/src/team_agent/sessions/__init__.py +0 -25
  310. package/src/team_agent/sessions/capture.py +0 -144
  311. package/src/team_agent/sessions/inventory.py +0 -44
  312. package/src/team_agent/sessions/resume.py +0 -135
  313. package/src/team_agent/simple_yaml.py +0 -236
  314. package/src/team_agent/spec.py +0 -370
  315. package/src/team_agent/state.py +0 -693
  316. package/src/team_agent/status/__init__.py +0 -63
  317. package/src/team_agent/status/approvals.py +0 -52
  318. package/src/team_agent/status/compact.py +0 -158
  319. package/src/team_agent/status/constants.py +0 -18
  320. package/src/team_agent/status/inbox.py +0 -58
  321. package/src/team_agent/status/peek.py +0 -117
  322. package/src/team_agent/status/queries.py +0 -199
  323. package/src/team_agent/task_graph.py +0 -80
  324. package/src/team_agent/terminal.py +0 -57
  325. package/src/team_agent/wake.py +0 -58
  326. package/src/team_agent/watch/__init__.py +0 -145
@@ -1,497 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import sqlite3
5
- import time
6
- import uuid
7
- from contextlib import closing
8
- from datetime import datetime, timedelta, timezone
9
- from pathlib import Path
10
- from typing import Any, Callable
11
-
12
- from . import agent_health as _agent_health
13
- from . import result_watchers as _result_watchers
14
- from .schema import SCHEMA_VERSION, initialize_schema, utcnow
15
- from .schema_migration import MANAGED_TABLE_LAYOUTS
16
- from team_agent.paths import runtime_dir
17
- from team_agent.spec import validate_result_envelope
18
-
19
-
20
- MESSAGE_SELECT = ", ".join(MANAGED_TABLE_LAYOUTS["messages"])
21
- RESULT_SELECT = ", ".join(MANAGED_TABLE_LAYOUTS["results"])
22
- SCHEDULED_EVENT_SELECT = ", ".join(MANAGED_TABLE_LAYOUTS["scheduled_events"])
23
- DELIVERY_TOKEN_SELECT = ", ".join(MANAGED_TABLE_LAYOUTS["delivery_tokens"])
24
-
25
-
26
- def _is_sqlite_locked(exc: sqlite3.OperationalError) -> bool:
27
- message = str(exc).lower()
28
- return (
29
- "database is locked" in message
30
- or "database table is locked" in message
31
- or "database schema is locked" in message
32
- )
33
-
34
-
35
- def _with_sqlite_busy_retry(action: Callable[[], None]) -> None:
36
- delay = 0.05
37
- for attempt in range(6):
38
- try:
39
- action()
40
- return
41
- except sqlite3.OperationalError as exc:
42
- if not _is_sqlite_locked(exc) or attempt == 5:
43
- raise
44
- time.sleep(delay)
45
- delay *= 2
46
-
47
-
48
- class MessageStore:
49
- SCHEMA_VERSION = SCHEMA_VERSION
50
-
51
- def __init__(self, workspace: Path):
52
- self.workspace = workspace
53
- self.path = runtime_dir(workspace) / "team.db"
54
- self.path.parent.mkdir(parents=True, exist_ok=True)
55
- self._init()
56
-
57
- def connect(self) -> sqlite3.Connection:
58
- conn = sqlite3.connect(self.path, timeout=30.0, isolation_level=None)
59
- conn.row_factory = sqlite3.Row
60
- conn.execute("PRAGMA busy_timeout=30000")
61
- conn.execute("PRAGMA journal_mode=WAL")
62
- return conn
63
-
64
- def _init(self) -> None:
65
- def initialize() -> None:
66
- with closing(self.connect()) as conn:
67
- initialize_schema(conn, self.path)
68
-
69
- _with_sqlite_busy_retry(initialize)
70
-
71
- def create_message(
72
- self,
73
- task_id: str | None,
74
- sender: str,
75
- recipient: str,
76
- content: str,
77
- reply_to: str | None = None,
78
- requires_ack: bool = True,
79
- artifact_refs: list[dict[str, Any]] | None = None,
80
- owner_team_id: str | None = None,
81
- ) -> str:
82
- message_id = f"msg_{uuid.uuid4().hex[:12]}"
83
- now = utcnow()
84
- with closing(self.connect()) as conn:
85
- with conn:
86
- conn.execute(
87
- """
88
- insert into messages(
89
- message_id, owner_team_id, task_id, sender, recipient, reply_to, requires_ack,
90
- status, content, artifact_refs, created_at, updated_at,
91
- delivered_at, acknowledged_at, error, delivery_attempts
92
- )
93
- values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
94
- """,
95
- (
96
- message_id,
97
- owner_team_id,
98
- task_id,
99
- sender,
100
- recipient,
101
- reply_to,
102
- int(requires_ack),
103
- "accepted",
104
- content,
105
- json.dumps(artifact_refs or []),
106
- now,
107
- now,
108
- None,
109
- None,
110
- None,
111
- 0,
112
- ),
113
- )
114
- return message_id
115
-
116
- def mark(self, message_id: str, status: str, error: str | None = None) -> None:
117
- now = utcnow()
118
- delivered_at = now if status in {"injected", "visible", "submitted", "submitted_unverified", "delivered"} else None
119
- acknowledged_at = now if status == "acknowledged" else None
120
- with closing(self.connect()) as conn:
121
- with conn:
122
- conn.execute(
123
- """
124
- update messages
125
- set status = case
126
- when status = 'acknowledged'
127
- and ? in ('injected', 'visible', 'submitted', 'submitted_unverified', 'delivered')
128
- then status
129
- else ?
130
- end,
131
- updated_at = ?,
132
- delivered_at = coalesce(?, delivered_at),
133
- acknowledged_at = coalesce(?, acknowledged_at),
134
- error = coalesce(?, error)
135
- where message_id = ?
136
- """,
137
- (status, status, now, delivered_at, acknowledged_at, error, message_id),
138
- )
139
- if status in {
140
- "injected",
141
- "visible",
142
- "submitted",
143
- "submitted_unverified",
144
- "injected_unverified",
145
- "delivery_blocked",
146
- "failed",
147
- }:
148
- conn.execute(
149
- """
150
- insert into delivery_tokens(
151
- message_id, unique_token, injected_at, visible_at, failed_at, failure_reason
152
- )
153
- values (?, ?, ?, ?, ?, ?)
154
- on conflict(message_id) do update set
155
- visible_at = coalesce(excluded.visible_at, delivery_tokens.visible_at),
156
- failed_at = coalesce(excluded.failed_at, delivery_tokens.failed_at),
157
- failure_reason = coalesce(excluded.failure_reason, delivery_tokens.failure_reason)
158
- """,
159
- (
160
- message_id,
161
- message_id,
162
- now,
163
- now if status in {"visible", "submitted"} else None,
164
- now if status in {"failed", "injected_unverified", "delivery_blocked"} else None,
165
- error if status in {"failed", "injected_unverified", "delivery_blocked"} else None,
166
- ),
167
- )
168
- if status == "acknowledged":
169
- conn.execute(
170
- "update delivery_tokens set consumed_at = coalesce(consumed_at, ?) where message_id = ?",
171
- (now, message_id),
172
- )
173
-
174
- def defer_delivery(self, message_id: str, status: str, reason: str) -> None:
175
- now = utcnow()
176
- with closing(self.connect()) as conn:
177
- with conn:
178
- conn.execute(
179
- """
180
- update messages
181
- set status = ?,
182
- updated_at = ?,
183
- error = ?,
184
- delivery_attempts = delivery_attempts + 1
185
- where message_id = ?
186
- """,
187
- (status, now, reason, message_id),
188
- )
189
-
190
- def claim_for_delivery(self, message_id: str) -> bool:
191
- now = utcnow()
192
- with closing(self.connect()) as conn:
193
- with conn:
194
- result = conn.execute(
195
- """
196
- update messages
197
- set status = 'target_resolved',
198
- updated_at = ?,
199
- delivery_attempts = delivery_attempts + 1
200
- where message_id = ?
201
- and status in ('pending', 'accepted', 'queued_until_idle', 'queued_until_start', 'queued_stopped', 'queued_pane_missing')
202
- """,
203
- (now, message_id),
204
- )
205
- return result.rowcount == 1
206
-
207
- def fail_timeouts(self, timeout_sec: int, exclude_recipients: set[str] | None = None) -> list[str]:
208
- cutoff = datetime.now(timezone.utc) - timedelta(seconds=timeout_sec)
209
- failed: list[str] = []
210
- exclude_recipients = exclude_recipients or set()
211
- with closing(self.connect()) as conn:
212
- with conn:
213
- rows = conn.execute(
214
- "select message_id, recipient, updated_at from messages where requires_ack = 1 and status in ('pending','accepted','target_resolved','injected','visible','submitted','delivered')"
215
- ).fetchall()
216
- for row in rows:
217
- if row["recipient"] in exclude_recipients:
218
- continue
219
- try:
220
- updated = datetime.fromisoformat(row["updated_at"])
221
- except ValueError:
222
- continue
223
- if updated < cutoff:
224
- failed.append(row["message_id"])
225
- conn.execute(
226
- "update messages set status = ?, updated_at = ?, error = ? where message_id = ?",
227
- ("failed", utcnow(), f"ack timeout after {timeout_sec}s", row["message_id"]),
228
- )
229
- return failed
230
-
231
- def messages(self, owner_team_id: str | None = None) -> list[dict[str, Any]]:
232
- with closing(self.connect()) as conn:
233
- if owner_team_id is None:
234
- rows = conn.execute(f"select {MESSAGE_SELECT} from messages order by created_at").fetchall()
235
- else:
236
- rows = conn.execute(
237
- f"select {MESSAGE_SELECT} from messages where owner_team_id = ? or owner_team_id is null order by created_at",
238
- (owner_team_id,),
239
- ).fetchall()
240
- return [dict(row) for row in rows]
241
-
242
- def inbox(self, agent_id: str, limit: int = 20, owner_team_id: str | None = None) -> list[dict[str, Any]]:
243
- with closing(self.connect()) as conn:
244
- if owner_team_id is None:
245
- rows = conn.execute(
246
- f"""
247
- select {MESSAGE_SELECT} from messages
248
- where sender = ? or recipient = ?
249
- order by created_at desc
250
- limit ?
251
- """,
252
- (agent_id, agent_id, limit),
253
- ).fetchall()
254
- else:
255
- rows = conn.execute(
256
- f"""
257
- select {MESSAGE_SELECT} from messages
258
- where (sender = ? or recipient = ?)
259
- and (owner_team_id = ? or owner_team_id is null)
260
- order by created_at desc
261
- limit ?
262
- """,
263
- (agent_id, agent_id, owner_team_id, limit),
264
- ).fetchall()
265
- return [dict(row) for row in reversed(rows)]
266
-
267
- def delivery_tokens(self) -> list[dict[str, Any]]:
268
- with closing(self.connect()) as conn:
269
- rows = conn.execute(f"select {DELIVERY_TOKEN_SELECT} from delivery_tokens order by injected_at").fetchall()
270
- return [dict(row) for row in rows]
271
-
272
- def add_scheduled_event(
273
- self,
274
- due_at: str,
275
- target: str,
276
- kind: str,
277
- payload: dict[str, Any],
278
- owner_team_id: str | None = None,
279
- ) -> int:
280
- with closing(self.connect()) as conn:
281
- with conn:
282
- cur = conn.execute(
283
- """
284
- insert into scheduled_events(owner_team_id, due_at, target, kind, payload_json, status, created_at)
285
- values (?, ?, ?, ?, ?, 'pending', ?)
286
- """,
287
- (owner_team_id, due_at, target, kind, json.dumps(payload, ensure_ascii=False), utcnow()),
288
- )
289
- return int(cur.lastrowid)
290
-
291
- def due_scheduled_events(self, now: str | None = None, owner_team_id: str | None = None) -> list[dict[str, Any]]:
292
- with closing(self.connect()) as conn:
293
- if owner_team_id is None:
294
- rows = conn.execute(
295
- f"""
296
- select {SCHEDULED_EVENT_SELECT} from scheduled_events
297
- where status = 'pending' and due_at <= ?
298
- order by due_at, id
299
- """,
300
- (now or utcnow(),),
301
- ).fetchall()
302
- else:
303
- rows = conn.execute(
304
- f"""
305
- select {SCHEDULED_EVENT_SELECT} from scheduled_events
306
- where status = 'pending' and due_at <= ?
307
- and (owner_team_id = ? or owner_team_id is null)
308
- order by due_at, id
309
- """,
310
- (now or utcnow(), owner_team_id),
311
- ).fetchall()
312
- return [dict(row) for row in rows]
313
-
314
- def mark_scheduled_event(self, event_id: int, status: str, result: dict[str, Any]) -> None:
315
- with closing(self.connect()) as conn:
316
- with conn:
317
- conn.execute(
318
- """
319
- update scheduled_events
320
- set status = ?, fired_at = ?, result_json = ?
321
- where id = ?
322
- """,
323
- (status, utcnow(), json.dumps(result, ensure_ascii=False), event_id),
324
- )
325
-
326
- def allow_peer(self, a: str, b: str) -> None:
327
- now = utcnow()
328
- pairs = [(a, b), (b, a)]
329
- with closing(self.connect()) as conn:
330
- with conn:
331
- conn.executemany(
332
- "insert or ignore into peer_allowlist(a, b, created_at) values (?, ?, ?)",
333
- [(left, right, now) for left, right in pairs],
334
- )
335
-
336
- def peer_allowed(self, a: str, b: str) -> bool:
337
- with closing(self.connect()) as conn:
338
- row = conn.execute("select 1 from peer_allowlist where a = ? and b = ?", (a, b)).fetchone()
339
- return row is not None
340
-
341
- def message_counts(self) -> dict[str, int]:
342
- counts: dict[str, int] = {}
343
- with closing(self.connect()) as conn:
344
- rows = conn.execute("select status, count(*) as n from messages group by status").fetchall()
345
- for row in rows:
346
- counts[row["status"]] = row["n"]
347
- return counts
348
-
349
- def result_counts(self) -> dict[str, Any]:
350
- counts: dict[str, Any] = {"total": 0, "uncollected": 0, "collected": 0, "invalid": 0, "by_status": {}}
351
- with closing(self.connect()) as conn:
352
- rows = conn.execute("select status, count(*) as n from results group by status").fetchall()
353
- for row in rows:
354
- status = row["status"]
355
- n = row["n"]
356
- counts["total"] += n
357
- if status == "collected":
358
- counts["collected"] += n
359
- elif status == "invalid":
360
- counts["invalid"] += n
361
- else:
362
- counts["uncollected"] += n
363
- counts["by_status"][status] = n
364
- return counts
365
-
366
- def add_result(self, envelope: dict[str, Any], owner_team_id: str | None = None) -> str:
367
- validate_result_envelope(envelope)
368
- result_id = f"res_{uuid.uuid4().hex[:12]}"
369
- with closing(self.connect()) as conn:
370
- with conn:
371
- conn.execute(
372
- """
373
- insert into results(owner_team_id, result_id, task_id, agent_id, envelope, status, created_at)
374
- values (?, ?, ?, ?, ?, ?, ?)
375
- """,
376
- (
377
- owner_team_id,
378
- result_id,
379
- envelope["task_id"],
380
- envelope["agent_id"],
381
- json.dumps(envelope, ensure_ascii=False),
382
- envelope["status"],
383
- utcnow(),
384
- ),
385
- )
386
- return result_id
387
-
388
- def acknowledge_task_messages(self, task_id: str, agent_id: str, owner_team_id: str | None = None) -> list[str]:
389
- now = utcnow()
390
- owner_clause = "and (owner_team_id = ? or owner_team_id is null)" if owner_team_id else ""
391
- owner_args = (owner_team_id,) if owner_team_id else ()
392
- with closing(self.connect()) as conn:
393
- with conn:
394
- rows = conn.execute(
395
- f"""
396
- select message_id from messages
397
- where task_id = ? and recipient = ? {owner_clause}
398
- and status in ('pending', 'accepted', 'target_resolved', 'injected', 'visible', 'submitted', 'delivered')
399
- """,
400
- (task_id, agent_id, *owner_args),
401
- ).fetchall()
402
- ids = [row["message_id"] for row in rows]
403
- conn.execute(
404
- f"""
405
- update messages
406
- set status = 'acknowledged', acknowledged_at = ?, updated_at = ?
407
- where task_id = ? and recipient = ? {owner_clause}
408
- and status in ('pending', 'accepted', 'target_resolved', 'injected', 'visible', 'submitted', 'delivered')
409
- """,
410
- (now, now, task_id, agent_id, *owner_args),
411
- )
412
- return ids
413
-
414
- def acknowledge_message(self, message_id: str, agent_id: str, owner_team_id: str | None = None) -> list[str]:
415
- now = utcnow()
416
- owner_clause = "and (owner_team_id = ? or owner_team_id is null)" if owner_team_id else ""
417
- owner_args = (owner_team_id,) if owner_team_id else ()
418
- with closing(self.connect()) as conn:
419
- with conn:
420
- row = conn.execute(
421
- f"""
422
- select message_id from messages
423
- where message_id = ? and recipient = ? {owner_clause}
424
- and status in ('pending', 'accepted', 'target_resolved', 'injected', 'visible', 'submitted', 'delivered')
425
- """,
426
- (message_id, agent_id, *owner_args),
427
- ).fetchone()
428
- if not row:
429
- return []
430
- conn.execute(
431
- f"""
432
- update messages
433
- set status = 'acknowledged', acknowledged_at = ?, updated_at = ?
434
- where message_id = ? and recipient = ? {owner_clause}
435
- and status in ('pending', 'accepted', 'target_resolved', 'injected', 'visible', 'submitted', 'delivered')
436
- """,
437
- (now, now, message_id, agent_id, *owner_args),
438
- )
439
- return [message_id]
440
-
441
- def results(self, uncollected_only: bool = False, owner_team_id: str | None = None) -> list[dict[str, Any]]:
442
- _ = owner_team_id
443
- clauses: list[str] = []
444
- args: list[Any] = []
445
- if uncollected_only:
446
- clauses.append("status not in ('collected', 'invalid')")
447
- where = " where " + " and ".join(clauses) if clauses else ""
448
- query = f"select {RESULT_SELECT} from results{where} order by created_at"
449
- with closing(self.connect()) as conn:
450
- rows = conn.execute(query, args).fetchall()
451
- return [dict(row) for row in rows]
452
-
453
- def result_by_id(self, result_id: str) -> dict[str, Any] | None:
454
- with closing(self.connect()) as conn:
455
- row = conn.execute(f"select {RESULT_SELECT} from results where result_id = ?", (result_id,)).fetchone()
456
- return dict(row) if row else None
457
-
458
- def latest_results(self, limit: int = 5, owner_team_id: str | None = None) -> list[dict[str, Any]]:
459
- owner_clause = "and owner_team_id = ?" if owner_team_id else ""
460
- args: tuple[Any, ...] = (owner_team_id, limit) if owner_team_id else (limit,)
461
- with closing(self.connect()) as conn:
462
- rows = conn.execute(
463
- f"""
464
- select {RESULT_SELECT} from results
465
- where status != 'invalid' {owner_clause}
466
- order by created_at desc
467
- limit ?
468
- """,
469
- args,
470
- ).fetchall()
471
- return [dict(row) for row in reversed(rows)]
472
-
473
- def mark_result_collected(self, result_id: str) -> None:
474
- with closing(self.connect()) as conn:
475
- with conn:
476
- conn.execute("update results set status = 'collected' where result_id = ?", (result_id,))
477
-
478
- def mark_result_invalid(self, result_id: str, error: str) -> None:
479
- with closing(self.connect()) as conn:
480
- with conn:
481
- conn.execute(
482
- "update results set status = 'invalid' where result_id = ?",
483
- (result_id,),
484
- )
485
-
486
-
487
-
488
- MessageStore.upsert_agent_health = _agent_health.upsert_agent_health
489
- MessageStore.agent_health = _agent_health.agent_health
490
- MessageStore.delete_agent_health = _agent_health.delete_agent_health
491
- MessageStore.gc_agent_health = _agent_health.gc_agent_health
492
- MessageStore.create_result_watcher = _result_watchers.create_result_watcher
493
- MessageStore.pending_result_watchers = _result_watchers.pending_result_watchers
494
- MessageStore.retryable_result_watchers = _result_watchers.retryable_result_watchers
495
- MessageStore.result_watchers = _result_watchers.result_watchers
496
- MessageStore.mark_result_watcher = _result_watchers.mark_result_watcher
497
- MessageStore.requeue_delivery_exhausted_watchers = _result_watchers.requeue_delivery_exhausted_watchers