bazaar-compute-node 0.2.0rc4__tar.gz → 0.2.0rc5__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 (199) hide show
  1. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/PKG-INFO +1 -1
  2. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/pyproject.toml +1 -1
  3. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/pyproject.toml.orig +1 -1
  4. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/process.py +72 -3
  5. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/runtime.py +19 -30
  6. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/process.py +100 -23
  7. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/runtime.py +10 -84
  8. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/codec.py +7 -4
  9. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/registry.py +2 -0
  10. bazaar_compute_node-0.2.0rc5/src/bazaar_compute_node/contrib/sqlite/migrations/v27_name_dms_by_the_peer_id.py +160 -0
  11. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/messages.py +11 -1
  12. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/storage.py +1 -0
  13. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/channel.py +11 -14
  14. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/outbound.py +45 -2
  15. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/channel.py +10 -0
  16. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/command.py +259 -95
  17. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/delivery.py +15 -0
  18. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/orchestrator.py +43 -109
  19. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/outcomes.py +1 -0
  20. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/runtime.py +1 -8
  21. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/storage.py +24 -17
  22. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/LICENSE +0 -0
  23. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/README.md +0 -0
  24. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/__init__.py +0 -0
  25. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/__init__.py +0 -0
  26. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/agent.py +0 -0
  27. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/agent_management.py +0 -0
  28. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/application.py +0 -0
  29. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/attachments.py +0 -0
  30. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/command.py +0 -0
  31. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/config.py +0 -0
  32. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/registry.py +0 -0
  33. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/resource_dispatch.py +0 -0
  34. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/system_service.py +0 -0
  35. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/transport.py +0 -0
  36. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/upgrade.py +0 -0
  37. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/usage.py +0 -0
  38. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/version_check.py +0 -0
  39. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/windows_pipe.py +0 -0
  40. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/wrapper.py +0 -0
  41. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/bcc.py +0 -0
  42. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cli.py +0 -0
  43. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/__init__.py +0 -0
  44. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/__init__.py +0 -0
  45. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/_client.py +0 -0
  46. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/_format.py +0 -0
  47. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/inbox.py +0 -0
  48. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/message.py +0 -0
  49. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/node.py +0 -0
  50. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/reminder.py +0 -0
  51. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/thread.py +0 -0
  52. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/__init__.py +0 -0
  53. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/_options.py +0 -0
  54. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/_runner.py +0 -0
  55. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/agent.py +0 -0
  56. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/node.py +0 -0
  57. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/service.py +0 -0
  58. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/__init__.py +0 -0
  59. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/__init__.py +0 -0
  60. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/approval.py +0 -0
  61. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/client.py +0 -0
  62. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/events.py +0 -0
  63. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/plugin.py +0 -0
  64. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/protocol.py +0 -0
  65. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/__init__.py +0 -0
  66. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/approval.py +0 -0
  67. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/client.py +0 -0
  68. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/events.py +0 -0
  69. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/plugin.py +0 -0
  70. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/protocol.py +0 -0
  71. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/__init__.py +0 -0
  72. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/api.py +0 -0
  73. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/approval.py +0 -0
  74. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/attachments.py +0 -0
  75. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/channel.py +0 -0
  76. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/frame.py +0 -0
  77. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/identity.py +0 -0
  78. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/outbound.py +0 -0
  79. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/plugin.py +0 -0
  80. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/transport.py +0 -0
  81. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/logging/__init__.py +0 -0
  82. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/logging/audit.py +0 -0
  83. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/logging/plugin.py +0 -0
  84. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/__init__.py +0 -0
  85. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/database.py +0 -0
  86. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/executor.py +0 -0
  87. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/__init__.py +0 -0
  88. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/model.py +0 -0
  89. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v01_initial_node_schema.py +0 -0
  90. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v02_session_mapping_indexes.py +0 -0
  91. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v03_message_log_indexes.py +0 -0
  92. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v04_runtime_attempt_facts.py +0 -0
  93. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v05_inbound_message_references.py +0 -0
  94. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v06_inbound_message_reference_integrity.py +0 -0
  95. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v07_inbound_provider_identity.py +0 -0
  96. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v08_transient_stream_events.py +0 -0
  97. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v09_remove_runtime_events.py +0 -0
  98. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v10_add_outbound_attachments.py +0 -0
  99. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v11_remove_runtime_session_mapping.py +0 -0
  100. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v12_add_reminders.py +0 -0
  101. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v13_add_agent_ownership.py +0 -0
  102. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v14_add_inbox_discovery_indexes.py +0 -0
  103. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v15_add_handoffs.py +0 -0
  104. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v16_remove_outbound_drafts.py +0 -0
  105. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v17_remove_agent_identity_triggers.py +0 -0
  106. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v18_unify_messages.py +0 -0
  107. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v19_reminder_system_messages.py +0 -0
  108. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v20_remove_freshness_persistence.py +0 -0
  109. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v21_remove_handoffs.py +0 -0
  110. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v22_readable_targets.py +0 -0
  111. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v23_persist_sender_identity.py +0 -0
  112. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v24_persist_sender_display_name.py +0 -0
  113. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v25_rename_sessions_to_threads.py +0 -0
  114. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/v26_remove_handoff_messages.py +0 -0
  115. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/plugin.py +0 -0
  116. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/reminder_codec.py +0 -0
  117. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/__init__.py +0 -0
  118. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/base.py +0 -0
  119. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/facade.py +0 -0
  120. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/reminders.py +0 -0
  121. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/sessions.py +0 -0
  122. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/__init__.py +0 -0
  123. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/api.py +0 -0
  124. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/approval.py +0 -0
  125. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/attachments.py +0 -0
  126. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/identity.py +0 -0
  127. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/markdown.py +0 -0
  128. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/plugin.py +0 -0
  129. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/wecom/__init__.py +0 -0
  130. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/wecom/channel.py +0 -0
  131. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/wecom/outbound.py +0 -0
  132. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/wecom/plugin.py +0 -0
  133. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/__init__.py +0 -0
  134. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/actor.py +0 -0
  135. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/agent.py +0 -0
  136. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/approval.py +0 -0
  137. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/audit.py +0 -0
  138. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/client.py +0 -0
  139. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/command.py +0 -0
  140. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/concurrency.py +0 -0
  141. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/correlation.py +0 -0
  142. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/inbox.py +0 -0
  143. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/instruction.py +0 -0
  144. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/lifecycle.py +0 -0
  145. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/__init__.py +0 -0
  146. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/entities.py +0 -0
  147. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/events.py +0 -0
  148. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/reminder.py +0 -0
  149. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/reminder_owner.py +0 -0
  150. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/states.py +0 -0
  151. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/observability.py +0 -0
  152. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/__init__.py +0 -0
  153. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/error_feedback.py +0 -0
  154. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/reminder.py +0 -0
  155. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/reminder_command.py +0 -0
  156. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/services.py +0 -0
  157. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/turn.py +0 -0
  158. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/upgrade_notice.py +0 -0
  159. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/paths.py +0 -0
  160. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/reminder.py +0 -0
  161. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/reminder_schedule.py +0 -0
  162. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/restart.py +0 -0
  163. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/timerwheel.py +0 -0
  164. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/__init__.py +0 -0
  165. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/clock.py +0 -0
  166. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/line_reader.py +0 -0
  167. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/markdown.py +0 -0
  168. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/sanitization.py +0 -0
  169. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/text.py +0 -0
  170. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/i18n/__init__.py +0 -0
  171. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/i18n/catalog.py +0 -0
  172. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/rendering.py +0 -0
  173. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/approval_no_person.tpl +0 -0
  174. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/check.tpl +0 -0
  175. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/error.tpl +0 -0
  176. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/inbox_check.tpl +0 -0
  177. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/read.tpl +0 -0
  178. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/reminder_list.tpl +0 -0
  179. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/reminder_mutation.tpl +0 -0
  180. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/reminder_schedule.tpl +0 -0
  181. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/unfollow.tpl +0 -0
  182. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/upgrade.tpl +0 -0
  183. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/version.tpl +0 -0
  184. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/attachment_suffix.tpl +0 -0
  185. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/check_message.tpl +0 -0
  186. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/freshness_hold.tpl +0 -0
  187. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/read_message.tpl +0 -0
  188. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/send_result.tpl +0 -0
  189. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/sender.tpl +0 -0
  190. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/developer_instructions.md +0 -0
  191. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/inbox_notice.tpl +0 -0
  192. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/locales/en.toml +0 -0
  193. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/locales/zh-CN.toml +0 -0
  194. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/launchd.plist +0 -0
  195. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/launchd.sh +0 -0
  196. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/systemd.service +0 -0
  197. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/windows.ps1 +0 -0
  198. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/windows.vbs +0 -0
  199. {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/windows.xml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bazaar-compute-node
3
- Version: 0.2.0rc4
3
+ Version: 0.2.0rc5
4
4
  Summary: Runtime-agnostic computer node daemon for agents and channels.
5
5
  License-Expression: AGPL-3.0-only
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bazaar-compute-node"
3
- version = "0.2.0rc4"
3
+ version = "0.2.0rc5"
4
4
  description = "Runtime-agnostic computer node daemon for agents and channels."
5
5
  readme = "README.md"
6
6
  license = "AGPL-3.0-only"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bazaar-compute-node"
3
- version = "0.2.0rc4"
3
+ version = "0.2.0rc5"
4
4
  description = "Runtime-agnostic computer node daemon for agents and channels."
5
5
  readme = "README.md"
6
6
  license = "AGPL-3.0-only"
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import json
5
+ import logging
5
6
  from collections import deque
6
7
  from collections.abc import Mapping
7
8
  from dataclasses import dataclass
@@ -22,6 +23,8 @@ from .protocol import (
22
23
  MAX_JSONL_BYTES = 1024 * 1024
23
24
  _EXIT_PIPE_DRAIN_SECONDS = 1
24
25
  _CLOSED = object()
26
+ _REAP_REPORT_SECONDS = 30.0
27
+ _LOGGER = logging.getLogger("bazaar_compute_node.runtime.claude.process")
25
28
 
26
29
 
27
30
  class ProcessState(StrEnum):
@@ -120,6 +123,8 @@ class ProcessSupervisor:
120
123
  self._write_lock = asyncio.Lock()
121
124
  self._lifecycle_lock = asyncio.Lock()
122
125
  self._exit_event = asyncio.Event()
126
+ self._abandoned: set[asyncio.Task[None]] = set()
127
+ self._started = False
123
128
 
124
129
  @property
125
130
  def state(self) -> ProcessState:
@@ -147,8 +152,9 @@ class ProcessSupervisor:
147
152
 
148
153
  async def start(self, *, timeout: float) -> None:
149
154
  async with self._lifecycle_lock:
150
- if self.is_running:
151
- return
155
+ if self._started:
156
+ raise RuntimeError("a stopped supervisor cannot start again")
157
+ self._started = True
152
158
  self._state = ProcessState.RUNNING
153
159
  try:
154
160
  async with asyncio.timeout(timeout):
@@ -227,6 +233,7 @@ class ProcessSupervisor:
227
233
  now = asyncio.get_running_loop().time()
228
234
  graceful_deadline = now + timeout * 0.6
229
235
  terminate_deadline = now + timeout * 0.9
236
+ kill_deadline = now + timeout
230
237
  if process.stdin is not None:
231
238
  process.stdin.close()
232
239
  try:
@@ -237,12 +244,74 @@ class ProcessSupervisor:
237
244
  await self._wait_until(process, terminate_deadline)
238
245
  except TimeoutError:
239
246
  process.kill()
240
- await process.wait()
247
+ try:
248
+ await self._wait_until(process, kill_deadline)
249
+ except TimeoutError:
250
+ # a process that survived a kill will not be waited out,
251
+ # so let go of it here instead of holding the lifecycle
252
+ # lock
253
+ self._abandon(process)
254
+ self._state = ProcessState.STOPPED
255
+ self._exit_event.set()
256
+ return
241
257
  self._returncode = process.returncode
242
258
  await self._join_tasks(cancel=True)
243
259
  self._state = ProcessState.STOPPED
244
260
  self._exit_event.set()
245
261
 
262
+ def _abandon(self, process: asyncio.subprocess.Process) -> None:
263
+ """Give up on a process without losing track of it.
264
+
265
+ Closing this side of the pipes is what unblocks everything: the readers
266
+ stop waiting for an EOF that a grandchild holding the write end will
267
+ never deliver, and the exit waiters can complete once the pipes count as
268
+ disconnected. Whoever still holds that write end is free to keep it.
269
+ """
270
+
271
+ transport = getattr(process, "_transport", None)
272
+ if transport is not None:
273
+ for fd in (1, 2):
274
+ pipe = transport.get_pipe_transport(fd)
275
+ if pipe is not None:
276
+ pipe.close()
277
+ # the watcher normally closes the queue, and it is about to be
278
+ # cancelled, so release whoever is already waiting in receive()
279
+ self._incoming.put_nowait(_CLOSED)
280
+ tasks = tuple(
281
+ task
282
+ for task in (self._stdout_task, self._stderr_task, self._watch_task)
283
+ if task is not None and task is not asyncio.current_task()
284
+ )
285
+ for task in tasks:
286
+ task.cancel()
287
+ self._stdout_task = None
288
+ self._stderr_task = None
289
+ self._watch_task = None
290
+ self._process = None
291
+ reaper = asyncio.create_task(
292
+ self._reap(process, tasks),
293
+ name=f"bcn-claude-reap-{process.pid}",
294
+ )
295
+ self._abandoned.add(reaper)
296
+ reaper.add_done_callback(self._abandoned.discard)
297
+
298
+ async def _reap(
299
+ self,
300
+ process: asyncio.subprocess.Process,
301
+ tasks: tuple[asyncio.Task[None], ...],
302
+ ) -> None:
303
+ """Outlive the caller waiting for a process nobody else is waiting for."""
304
+
305
+ if tasks:
306
+ await asyncio.gather(*tasks, return_exceptions=True)
307
+ try:
308
+ async with asyncio.timeout(_REAP_REPORT_SECONDS):
309
+ returncode = await process.wait()
310
+ except TimeoutError:
311
+ _LOGGER.warning("process %s outlived its kill; still waiting", process.pid)
312
+ returncode = await process.wait()
313
+ self._returncode = returncode
314
+
246
315
  async def _read_stdout(self, process: asyncio.subprocess.Process) -> None:
247
316
  stdout = process.stdout
248
317
  if stdout is None:
@@ -25,7 +25,6 @@ from ...core.paths import resolve_workspace_dir
25
25
  from ...core.runtime import (
26
26
  IRuntime,
27
27
  IRuntimeTurnStream,
28
- RuntimeBackgroundIdle,
29
28
  RuntimeCommandContext,
30
29
  RuntimeLifecycleEvent,
31
30
  RuntimeSandboxMode,
@@ -60,7 +59,6 @@ class _Connection:
60
59
  queued_human_cycle_started: asyncio.Event = field(default_factory=asyncio.Event)
61
60
  active_stream: TurnEventStream | None = None
62
61
  active_background_task_ids: set[str] = field(default_factory=set)
63
- background_active: bool = False
64
62
 
65
63
 
66
64
  class Runtime(IRuntime, IAsyncLifecycle):
@@ -507,8 +505,7 @@ class Runtime(IRuntime, IAsyncLifecycle):
507
505
  self._retirement_tasks.add(task)
508
506
  task.add_done_callback(self._retirement_tasks.discard)
509
507
  return
510
- if _observe_background(connection, message):
511
- self._lifecycle_events.put_nowait(RuntimeBackgroundIdle(session.id))
508
+ _observe_background(connection, message)
512
509
 
513
510
  client.set_message_observer(observe)
514
511
  return connection
@@ -595,32 +592,24 @@ def _sandbox_settings(
595
592
  return settings
596
593
 
597
594
 
598
- def _observe_background(connection: _Connection, message: dict[str, object]) -> bool:
599
- was_active = connection.background_active
600
- if message.get("type") == "system":
601
- subtype = message.get("subtype")
602
- task_id = message.get("task_id")
603
- if isinstance(task_id, str) and task_id:
604
- if subtype == "task_started" and message.get("task_type") in {
605
- "local_agent",
606
- "local_workflow",
607
- }:
608
- connection.active_background_task_ids.add(task_id)
609
- elif subtype == "task_notification":
610
- connection.active_background_task_ids.discard(task_id)
611
- elif subtype == "task_updated":
612
- patch = message.get("patch")
613
- if isinstance(patch, dict) and patch.get("status") in {
614
- "completed",
615
- "failed",
616
- "stopped",
617
- "killed",
618
- }:
619
- connection.active_background_task_ids.discard(task_id)
620
- connection.background_active = bool(
621
- connection.active_background_task_ids or connection.client.provider_wake_active
622
- )
623
- return was_active and not connection.background_active
595
+ def _observe_background(connection: _Connection, message: dict[str, object]) -> None:
596
+ # Claude Code republishes the whole set on every change, so the latest
597
+ # snapshot is the answer and nothing has to be accumulated from edges
598
+ if (
599
+ message.get("type") != "system"
600
+ or message.get("subtype") != "background_tasks_changed"
601
+ ):
602
+ return
603
+ tasks = message.get("tasks")
604
+ if not isinstance(tasks, list):
605
+ return
606
+ connection.active_background_task_ids = {
607
+ task_id
608
+ for task in tasks
609
+ if isinstance(task, dict)
610
+ and isinstance(task_id := task.get("task_id"), str)
611
+ and task_id
612
+ }
624
613
 
625
614
 
626
615
  def _provider_result(error: BaseException) -> ProviderCallResult[Any]:
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import json
5
+ import logging
5
6
  import os
6
7
  import signal
7
8
  from collections import deque
@@ -60,6 +61,8 @@ class JsonlProcessSpec:
60
61
 
61
62
 
62
63
  _QUEUE_CLOSED = object()
64
+ _REAP_REPORT_SECONDS = 30.0
65
+ _LOGGER = logging.getLogger("bazaar_compute_node.runtime.codex.process")
63
66
 
64
67
 
65
68
  class JsonlProcessSupervisor:
@@ -93,6 +96,8 @@ class JsonlProcessSupervisor:
93
96
  self._pending: dict[JsonlRequestId, asyncio.Future[JsonlMessage]] = {}
94
97
  self._next_request_id = 0
95
98
  self._closed_message_sent = False
99
+ self._abandoned: set[asyncio.Task[None]] = set()
100
+ self._started = False
96
101
 
97
102
  @property
98
103
  def state(self) -> JsonlProcessState:
@@ -123,10 +128,9 @@ class JsonlProcessSupervisor:
123
128
  async def start(self, *, timeout: float) -> None:
124
129
  _validate_timeout(timeout)
125
130
  async with self._lifecycle_lock:
126
- if self.is_running:
127
- return
128
- await self._join_tasks()
129
- self._reset_runtime_state()
131
+ if self._started:
132
+ raise RuntimeError("a stopped supervisor cannot start again")
133
+ self._started = True
130
134
  self._state = JsonlProcessState.STARTING
131
135
  try:
132
136
  async with asyncio.timeout(timeout):
@@ -171,19 +175,42 @@ class JsonlProcessSupervisor:
171
175
  self._send_closed_message()
172
176
  return
173
177
  self._state = JsonlProcessState.STOPPING
174
- deadline = asyncio.get_running_loop().time() + timeout
178
+ now = asyncio.get_running_loop().time()
179
+ graceful_deadline = now + timeout * 0.6
180
+ terminate_deadline = now + timeout * 0.8
181
+ kill_deadline = now + timeout * 0.9
182
+ deadline = now + timeout
175
183
  if process.stdin is not None:
176
184
  process.stdin.close()
177
185
  try:
178
- await self._wait_for_process(process, deadline)
186
+ await self._wait_for_process(process, graceful_deadline)
179
187
  except TimeoutError:
180
188
  _terminate_process(process)
181
189
  try:
182
- await self._wait_for_process(process, deadline)
190
+ await self._wait_for_process(process, terminate_deadline)
183
191
  except TimeoutError:
184
192
  _kill_process(process)
185
- await process.wait()
186
- await self._join_tasks()
193
+ try:
194
+ await self._wait_for_process(process, kill_deadline)
195
+ except TimeoutError:
196
+ # a process that survived SIGKILL will not be waited out,
197
+ # so let go of it here instead of holding the lifecycle
198
+ # lock
199
+ self._abandon(process)
200
+ self._state = JsonlProcessState.STOPPED
201
+ self._send_closed_message()
202
+ return
203
+ # an exited process is no guarantee of EOF: a background command it
204
+ # left behind can hold the pipes open, and then the readers never
205
+ # finish on their own either
206
+ remaining = deadline - asyncio.get_running_loop().time()
207
+ try:
208
+ if remaining <= 0:
209
+ raise TimeoutError
210
+ async with asyncio.timeout(remaining):
211
+ await self._join_tasks()
212
+ except TimeoutError:
213
+ self._abandon(process)
187
214
  self._state = JsonlProcessState.STOPPED
188
215
  self._send_closed_message()
189
216
 
@@ -493,6 +520,70 @@ class JsonlProcessSupervisor:
493
520
  async with asyncio.timeout(remaining):
494
521
  await asyncio.shield(process.wait())
495
522
 
523
+ def _abandon(self, process: asyncio.subprocess.Process) -> None:
524
+ """Give up on a process without losing track of it.
525
+
526
+ Closing this side of the pipes is what unblocks everything: the readers
527
+ stop waiting for an EOF that a grandchild holding the write end will
528
+ never deliver, and the exit waiters can complete once the pipes count as
529
+ disconnected. Whoever still holds that write end is free to keep it.
530
+ """
531
+
532
+ transport = getattr(process, "_transport", None)
533
+ if transport is not None:
534
+ for fd in (1, 2):
535
+ pipe = transport.get_pipe_transport(fd)
536
+ if pipe is not None:
537
+ pipe.close()
538
+ # the watcher normally publishes the exit, and it is about to be
539
+ # cancelled, so release whoever is already waiting on it
540
+ self._exit_event.set()
541
+ pending = tuple(self._pending.values())
542
+ self._pending.clear()
543
+ # the process may already have exited here, and then its status is the
544
+ # honest answer; the reaper publishes the rest once it arrives
545
+ exited = JsonlProcessExited(
546
+ returncode=process.returncode,
547
+ stderr_tail=self.stderr_tail,
548
+ )
549
+ for future in pending:
550
+ if not future.done():
551
+ future.set_exception(exited)
552
+ tasks = tuple(
553
+ task
554
+ for task in (self._stdout_task, self._stderr_task, self._watch_task)
555
+ if task is not None and task is not asyncio.current_task()
556
+ )
557
+ for task in tasks:
558
+ task.cancel()
559
+ self._stdout_task = None
560
+ self._stderr_task = None
561
+ self._watch_task = None
562
+ self._process = None
563
+ reaper = asyncio.create_task(
564
+ self._reap(process, tasks),
565
+ name=f"bcn-codex-reap-{process.pid}",
566
+ )
567
+ self._abandoned.add(reaper)
568
+ reaper.add_done_callback(self._abandoned.discard)
569
+
570
+ async def _reap(
571
+ self,
572
+ process: asyncio.subprocess.Process,
573
+ tasks: tuple[asyncio.Task[None], ...],
574
+ ) -> None:
575
+ """Outlive the caller waiting for a process nobody else is waiting for."""
576
+
577
+ if tasks:
578
+ await asyncio.gather(*tasks, return_exceptions=True)
579
+ try:
580
+ async with asyncio.timeout(_REAP_REPORT_SECONDS):
581
+ returncode = await process.wait()
582
+ except TimeoutError:
583
+ _LOGGER.warning("process %s outlived its kill; still waiting", process.pid)
584
+ returncode = await process.wait()
585
+ self._returncode = returncode
586
+
496
587
  async def _join_tasks(self) -> None:
497
588
  tasks = tuple(
498
589
  task
@@ -505,20 +596,6 @@ class JsonlProcessSupervisor:
505
596
  self._stderr_task = None
506
597
  self._watch_task = None
507
598
 
508
- def _reset_runtime_state(self) -> None:
509
- while True:
510
- try:
511
- self._incoming.get_nowait()
512
- except asyncio.QueueEmpty:
513
- break
514
- self._stderr_tail.clear()
515
- self._returncode = None
516
- self._fatal_error = None
517
- self._next_request_id = 0
518
- self._closed_message_sent = False
519
- self._exit_event.clear()
520
- self._pending.clear()
521
-
522
599
  def _send_closed_message(self) -> None:
523
600
  if self._closed_message_sent:
524
601
  return
@@ -5,8 +5,8 @@ import json
5
5
  import logging
6
6
  import os
7
7
  import shutil
8
- from collections.abc import Callable, Mapping
9
- from dataclasses import dataclass, field, replace
8
+ from collections.abc import Callable
9
+ from dataclasses import dataclass, replace
10
10
  from functools import partial
11
11
  from pathlib import Path
12
12
  from typing import Any
@@ -24,7 +24,6 @@ from ...core.paths import resolve_workspace_dir
24
24
  from ...core.runtime import (
25
25
  IRuntime,
26
26
  IRuntimeTurnStream,
27
- RuntimeBackgroundIdle,
28
27
  RuntimeCommandContext,
29
28
  RuntimeExpire,
30
29
  RuntimeLifecycleEvent,
@@ -62,7 +61,6 @@ _INITIALIZE_ATTEMPTS = 2
62
61
  _RECONCILE_ATTEMPTS = 2
63
62
  _WORKSPACE_AGENTS_WATCH_ID = "bcn-agents-workspace"
64
63
  _CODEX_HOME_AGENTS_WATCH_ID = "bcn-agents-codex-home"
65
- _BACKGROUND_REFRESH_TIMEOUT_SECONDS = 10.0
66
64
 
67
65
 
68
66
  @dataclass(slots=True)
@@ -72,8 +70,6 @@ class _Connection:
72
70
  workspace: Path
73
71
  provider_thread_id: str
74
72
  active_turn_id: str | None = None
75
- background_state_lock: asyncio.Lock = field(default_factory=asyncio.Lock)
76
- background_job_present: bool = False
77
73
 
78
74
 
79
75
  class Runtime(IRuntime, IAsyncLifecycle):
@@ -113,7 +109,6 @@ class Runtime(IRuntime, IAsyncLifecycle):
113
109
  self._effort = effort
114
110
  self._connections: dict[str, _Connection] = {}
115
111
  self._lifecycle_events: asyncio.Queue[RuntimeLifecycleEvent] = asyncio.Queue()
116
- self._background_refresh_tasks: set[asyncio.Task[None]] = set()
117
112
  self._logger = logging.getLogger("bazaar_compute_node.runtime.codex")
118
113
  self._started = False
119
114
  self._stopping = False
@@ -122,11 +117,6 @@ class Runtime(IRuntime, IAsyncLifecycle):
122
117
  del timeout
123
118
  if self._stopping:
124
119
  raise RuntimeError("Codex App Server runtime is stopping")
125
- if os.name == "nt":
126
- self._logger.warning(
127
- "Codex idle timeout is not supported on Windows; "
128
- "see openai/codex#15461."
129
- )
130
120
  self._started = True
131
121
 
132
122
  async def stop(self, *, timeout: float) -> None:
@@ -135,11 +125,6 @@ class Runtime(IRuntime, IAsyncLifecycle):
135
125
  self._stopping = True
136
126
  connections = tuple(self._connections.items())
137
127
  self._connections.clear()
138
- refresh_tasks = tuple(self._background_refresh_tasks)
139
- for task in refresh_tasks:
140
- task.cancel()
141
- if refresh_tasks:
142
- await asyncio.gather(*refresh_tasks, return_exceptions=True)
143
128
  for _, connection in connections:
144
129
  try:
145
130
  await connection.supervisor.stop(timeout=timeout)
@@ -519,25 +504,20 @@ class Runtime(IRuntime, IAsyncLifecycle):
519
504
  *,
520
505
  timeout: float,
521
506
  ) -> bool:
522
- if os.name == "nt":
523
- # Detached OS processes are not exposed by the Windows Codex provider.
524
- return True
525
507
  connection = self._connections.get(session.id)
526
508
  provider_thread_id = session.provider_thread_id
527
509
  if connection is None or not provider_thread_id:
528
510
  return False
529
511
  try:
530
- async with connection.background_state_lock:
531
- response = await connection.client.list_background_terminals(
532
- provider_thread_id,
533
- timeout=timeout,
534
- )
535
- present = parse_background_terminals_response(response)
536
- if self._connections.get(session.id) is connection:
537
- _record_background_state(connection, present)
512
+ response = await connection.client.list_background_terminals(
513
+ provider_thread_id,
514
+ timeout=timeout,
515
+ )
538
516
  except AppServerProtocolError, JsonlTransportError:
539
- return False
540
- return present
517
+ # a question the provider could not answer is not a no: report work
518
+ # so the caller keeps the session instead of recycling a busy one
519
+ return True
520
+ return parse_background_terminals_response(response)
541
521
 
542
522
  async def stop_session(
543
523
  self,
@@ -563,7 +543,6 @@ class Runtime(IRuntime, IAsyncLifecycle):
563
543
  *,
564
544
  targets: dict[str, Path],
565
545
  runtime_session_id: str,
566
- origin_holder: list[_Connection],
567
546
  ) -> bool:
568
547
  """Decide what a provider notification means for the session that owns it."""
569
548
 
@@ -572,27 +551,6 @@ class Runtime(IRuntime, IAsyncLifecycle):
572
551
  parse_skills_changed_notification(message)
573
552
  self._lifecycle_events.put_nowait(RuntimeExpire(runtime_session_id))
574
553
  return True
575
- if method == "item/completed" and os.name != "nt":
576
- params = message.get("params")
577
- item = params.get("item") if isinstance(params, Mapping) else None
578
- if (
579
- isinstance(params, Mapping)
580
- and isinstance(params.get("threadId"), str)
581
- and isinstance(item, Mapping)
582
- and item.get("type") == "commandExecution"
583
- ):
584
- if not origin_holder:
585
- return False
586
- origin = origin_holder[0]
587
- task = asyncio.create_task(
588
- self._refresh_background_state(
589
- runtime_session_id,
590
- origin,
591
- ),
592
- name=f"bcn-codex-background-{runtime_session_id}",
593
- )
594
- self._background_refresh_tasks.add(task)
595
- task.add_done_callback(self._background_refresh_tasks.discard)
596
554
  if method != "fs/changed":
597
555
  return False
598
556
  changed = parse_fs_changed_notification(message)
@@ -648,7 +606,6 @@ class Runtime(IRuntime, IAsyncLifecycle):
648
606
  environment = dict(self._context.environment_for_session(session))
649
607
  for attempt in range(_INITIALIZE_ATTEMPTS):
650
608
  watch_targets: dict[str, Path] = {}
651
- connection_holder: list[_Connection] = []
652
609
 
653
610
  supervisor = JsonlProcessSupervisor(
654
611
  JsonlProcessSpec(
@@ -661,7 +618,6 @@ class Runtime(IRuntime, IAsyncLifecycle):
661
618
  self._route_notification,
662
619
  targets=watch_targets,
663
620
  runtime_session_id=session.id,
664
- origin_holder=connection_holder,
665
621
  ),
666
622
  )
667
623
  client = Client(supervisor)
@@ -682,33 +638,9 @@ class Runtime(IRuntime, IAsyncLifecycle):
682
638
  workspace=workspace,
683
639
  provider_thread_id=session.provider_thread_id or "",
684
640
  )
685
- connection_holder.append(connection)
686
641
  return connection
687
642
  raise AssertionError("Codex initialization retry loop did not return")
688
643
 
689
- async def _refresh_background_state(
690
- self,
691
- session_id: str,
692
- connection: _Connection,
693
- ) -> None:
694
- if self._connections.get(session_id) is not connection:
695
- return
696
- async with connection.background_state_lock:
697
- if self._connections.get(session_id) is not connection:
698
- return
699
- try:
700
- response = await connection.client.list_background_terminals(
701
- connection.provider_thread_id,
702
- timeout=_BACKGROUND_REFRESH_TIMEOUT_SECONDS,
703
- )
704
- present = parse_background_terminals_response(response)
705
- except AppServerProtocolError, JsonlTransportError:
706
- return
707
- if self._connections.get(session_id) is not connection:
708
- return
709
- if _record_background_state(connection, present):
710
- self._lifecycle_events.put_nowait(RuntimeBackgroundIdle(session_id))
711
-
712
644
  async def _stop_connection(
713
645
  self,
714
646
  connection: _Connection,
@@ -730,12 +662,6 @@ class Runtime(IRuntime, IAsyncLifecycle):
730
662
  raise RuntimeError("Codex App Server runtime is not started")
731
663
 
732
664
 
733
- def _record_background_state(connection: _Connection, present: bool) -> bool:
734
- was_present = connection.background_job_present
735
- connection.background_job_present = present
736
- return was_present and not present
737
-
738
-
739
665
  def _provider_result(error: BaseException) -> ProviderCallResult[Any]:
740
666
  if isinstance(
741
667
  error,
@@ -294,9 +294,13 @@ def validate_outbound_message_input(message: object) -> None:
294
294
 
295
295
 
296
296
  def validate_outbound_insert(message: Message[OutboundAttachment]) -> None:
297
- if message.delivery_state is not OutboundDeliveryState.PENDING:
298
- raise ValueError("a new outbound message must start in pending state")
299
- if any(
297
+ """Check a message written once the provider has already answered.
298
+
299
+ An outbound is recorded after its attempt, so it arrives carrying whatever
300
+ became of it; only a message still waiting may claim to know nothing.
301
+ """
302
+
303
+ if message.delivery_state is OutboundDeliveryState.PENDING and any(
300
304
  value is not None
301
305
  for value in (
302
306
  message.provider_message_id,
@@ -442,7 +446,6 @@ def validate_channel_session_update(
442
446
  existing.channel != incoming.channel
443
447
  or existing.provider_thread_id != incoming.provider_thread_id
444
448
  or existing.target_kind is not incoming.target_kind
445
- or existing.created_at_ms != incoming.created_at_ms
446
449
  ):
447
450
  raise ValueError("channel session identity cannot change")
448
451
  _validate_updated_at(existing.updated_at_ms, incoming.updated_at_ms)
@@ -37,6 +37,7 @@ from .v23_persist_sender_identity import SENDER_IDENTITY_MIGRATION
37
37
  from .v24_persist_sender_display_name import SENDER_DISPLAY_NAME_MIGRATION
38
38
  from .v25_rename_sessions_to_threads import THREAD_RENAME_MIGRATION
39
39
  from .v26_remove_handoff_messages import HANDOFF_MESSAGE_REMOVAL_MIGRATION
40
+ from .v27_name_dms_by_the_peer_id import NAME_DM_BY_PEER_ID_MIGRATION
40
41
 
41
42
  if TYPE_CHECKING:
42
43
  from ..executor import SqliteSession
@@ -85,6 +86,7 @@ MIGRATIONS = _migration_ledger(
85
86
  SENDER_DISPLAY_NAME_MIGRATION,
86
87
  THREAD_RENAME_MIGRATION,
87
88
  HANDOFF_MESSAGE_REMOVAL_MIGRATION,
89
+ NAME_DM_BY_PEER_ID_MIGRATION,
88
90
  )
89
91
 
90
92