bazaar-compute-node 0.1.32__tar.gz → 0.1.34__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 (178) hide show
  1. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/PKG-INFO +2 -1
  2. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/pyproject.toml +2 -1
  3. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/pyproject.toml.orig +2 -1
  4. bazaar_compute_node-0.1.34/src/bazaar_compute_node/__init__.py +4 -0
  5. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/agent.py +83 -83
  6. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/agent_management.py +68 -25
  7. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/application.py +54 -7
  8. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/command.py +122 -144
  9. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/config.py +250 -118
  10. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/registry.py +10 -35
  11. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/resource_dispatch.py +104 -3
  12. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/system_service.py +70 -11
  13. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/transport.py +2 -2
  14. bazaar_compute_node-0.1.34/src/bazaar_compute_node/app/upgrade.py +309 -0
  15. bazaar_compute_node-0.1.34/src/bazaar_compute_node/app/version_check.py +87 -0
  16. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/bcc.py +221 -151
  17. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/cli.py +5 -2
  18. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/lark/channel.py +3 -1
  19. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/codec.py +8 -1
  20. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/__init__.py +2 -0
  21. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/registry.py +2 -0
  22. bazaar_compute_node-0.1.34/src/bazaar_compute_node/contrib/sqlite/migrations/v24_persist_sender_display_name.py +11 -0
  23. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/repository/messages.py +24 -6
  24. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/repository/reminders.py +54 -58
  25. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/telegram/channel.py +20 -4
  26. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/models/entities.py +21 -1
  27. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/orchestration/error_feedback.py +2 -2
  28. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/orchestration/reminder.py +80 -48
  29. bazaar_compute_node-0.1.34/src/bazaar_compute_node/core/orchestration/runtime_pool.py +62 -0
  30. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/orchestration/session.py +358 -208
  31. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/orchestration/turn.py +43 -36
  32. bazaar_compute_node-0.1.34/src/bazaar_compute_node/core/orchestration/upgrade_notice.py +25 -0
  33. bazaar_compute_node-0.1.34/src/bazaar_compute_node/core/restart.py +9 -0
  34. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/storage.py +15 -7
  35. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/bcc/check.tpl +4 -0
  36. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/bcc/error.tpl +4 -0
  37. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/bcc/inbox_list.tpl +3 -0
  38. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/bcc/inbox_target.tpl +1 -0
  39. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/bcc/read.tpl +5 -0
  40. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/bcc/reminder_list.tpl +2 -0
  41. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/bcc/reminder_mutation.tpl +2 -0
  42. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/bcc/reminder_schedule.tpl +2 -0
  43. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/bcc/unfollow.tpl +1 -0
  44. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/bcc/upgrade.tpl +2 -0
  45. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/bcc/version.tpl +1 -0
  46. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/command/attachment_suffix.tpl +1 -0
  47. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/command/check_message.tpl +8 -0
  48. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/command/freshness_hold.tpl +19 -0
  49. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/command/read_message.tpl +1 -0
  50. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/command/send_result.tpl +1 -0
  51. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/command/sender.tpl +1 -0
  52. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/inbox_notice.tpl +5 -0
  53. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/resources/locales/en.toml +2 -1
  54. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/resources/locales/zh-CN.toml +2 -1
  55. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/system_service/replace_managed_file.ps1 +13 -0
  56. bazaar_compute_node-0.1.34/src/bazaar_compute_node/resources/system_service/windows.ps1 +157 -0
  57. bazaar_compute_node-0.1.32/src/bazaar_compute_node/__init__.py +0 -3
  58. bazaar_compute_node-0.1.32/src/bazaar_compute_node/resources/system_service/windows.ps1 +0 -98
  59. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/LICENSE +0 -0
  60. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/README.md +0 -0
  61. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/__init__.py +0 -0
  62. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/attachments.py +0 -0
  63. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/windows_pipe.py +0 -0
  64. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/app/wrapper.py +0 -0
  65. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/__init__.py +0 -0
  66. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/claude/__init__.py +0 -0
  67. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/claude/approval.py +0 -0
  68. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/claude/client.py +0 -0
  69. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/claude/events.py +0 -0
  70. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/claude/plugin.py +0 -0
  71. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/claude/process.py +0 -0
  72. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/claude/protocol.py +0 -0
  73. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/claude/runtime.py +0 -0
  74. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/codex/__init__.py +0 -0
  75. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/codex/approval.py +0 -0
  76. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/codex/client.py +0 -0
  77. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/codex/events.py +0 -0
  78. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/codex/plugin.py +0 -0
  79. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/codex/process.py +0 -0
  80. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/codex/protocol.py +0 -0
  81. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/codex/runtime.py +0 -0
  82. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/lark/__init__.py +0 -0
  83. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/lark/api.py +0 -0
  84. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/lark/approval.py +0 -0
  85. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/lark/attachments.py +0 -0
  86. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/lark/frame.py +0 -0
  87. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/lark/identity.py +0 -0
  88. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/lark/outbound.py +0 -0
  89. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/lark/plugin.py +0 -0
  90. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/lark/transport.py +0 -0
  91. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/logging/__init__.py +0 -0
  92. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/logging/audit.py +0 -0
  93. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/logging/plugin.py +0 -0
  94. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/__init__.py +0 -0
  95. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/database.py +0 -0
  96. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/executor.py +0 -0
  97. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/model.py +0 -0
  98. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v01_initial_node_schema.py +0 -0
  99. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v02_session_mapping_indexes.py +0 -0
  100. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v03_message_log_indexes.py +0 -0
  101. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v04_runtime_attempt_facts.py +0 -0
  102. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v05_inbound_message_references.py +0 -0
  103. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v06_inbound_message_reference_integrity.py +0 -0
  104. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v07_inbound_provider_identity.py +0 -0
  105. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v08_transient_stream_events.py +0 -0
  106. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v09_remove_runtime_events.py +0 -0
  107. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v10_add_outbound_attachments.py +0 -0
  108. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v11_remove_runtime_session_mapping.py +0 -0
  109. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v12_add_reminders.py +0 -0
  110. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v13_add_agent_ownership.py +0 -0
  111. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v14_add_inbox_discovery_indexes.py +0 -0
  112. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v15_add_handoffs.py +0 -0
  113. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v16_remove_outbound_drafts.py +0 -0
  114. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v17_remove_agent_identity_triggers.py +0 -0
  115. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v18_unify_messages.py +0 -0
  116. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v19_reminder_system_messages.py +0 -0
  117. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v20_remove_freshness_persistence.py +0 -0
  118. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v21_remove_handoffs.py +0 -0
  119. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v22_readable_targets.py +0 -0
  120. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/migrations/v23_persist_sender_identity.py +0 -0
  121. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/plugin.py +0 -0
  122. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/reminder_codec.py +0 -0
  123. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/repository/__init__.py +0 -0
  124. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/repository/base.py +0 -0
  125. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/repository/facade.py +0 -0
  126. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/repository/sessions.py +0 -0
  127. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/sqlite/storage.py +0 -0
  128. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/telegram/__init__.py +0 -0
  129. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/telegram/api.py +0 -0
  130. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/telegram/approval.py +0 -0
  131. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/telegram/attachments.py +0 -0
  132. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/telegram/identity.py +0 -0
  133. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/telegram/markdown.py +0 -0
  134. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/telegram/outbound.py +0 -0
  135. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/telegram/plugin.py +0 -0
  136. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/wecom/__init__.py +0 -0
  137. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/wecom/channel.py +0 -0
  138. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/wecom/markdown.py +0 -0
  139. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/wecom/outbound.py +0 -0
  140. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/contrib/wecom/plugin.py +0 -0
  141. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/__init__.py +0 -0
  142. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/approval.py +0 -0
  143. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/audit.py +0 -0
  144. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/channel.py +0 -0
  145. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/client.py +0 -0
  146. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/command.py +0 -0
  147. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/concurrency.py +0 -0
  148. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/correlation.py +0 -0
  149. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/inbox.py +0 -0
  150. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/instruction.py +0 -0
  151. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/lifecycle.py +0 -0
  152. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/models/__init__.py +0 -0
  153. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/models/reminder.py +0 -0
  154. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/models/reminder_owner.py +0 -0
  155. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/models/states.py +0 -0
  156. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/observability.py +0 -0
  157. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/orchestration/__init__.py +0 -0
  158. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/orchestration/command.py +0 -0
  159. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/orchestration/delivery.py +0 -0
  160. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/orchestration/reminder_command.py +0 -0
  161. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/orchestration/services.py +0 -0
  162. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/outcomes.py +0 -0
  163. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/paths.py +0 -0
  164. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/reminder.py +0 -0
  165. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/reminder_schedule.py +0 -0
  166. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/runtime.py +0 -0
  167. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/timerwheel.py +0 -0
  168. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/utils/__init__.py +0 -0
  169. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/core/utils/line_reader.py +0 -0
  170. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/i18n/__init__.py +0 -0
  171. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/i18n/catalog.py +0 -0
  172. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/rendering.py +0 -0
  173. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/resources/developer_instructions.md +0 -0
  174. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/resources/system_service/launchd.plist +0 -0
  175. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/resources/system_service/launchd.sh +0 -0
  176. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/resources/system_service/systemd.service +0 -0
  177. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/src/bazaar_compute_node/resources/system_service/windows.vbs +0 -0
  178. {bazaar_compute_node-0.1.32 → bazaar_compute_node-0.1.34}/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.1.32
3
+ Version: 0.1.34
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
@@ -8,6 +8,7 @@ Requires-Dist: aiohttp>=3.12.0
8
8
  Requires-Dist: aiosqlite>=0.20.0
9
9
  Requires-Dist: cryptography>=45.0.0
10
10
  Requires-Dist: jinja2>=3.1.6
11
+ Requires-Dist: packaging>=25.0
11
12
  Requires-Dist: pydantic>=2.0.0
12
13
  Requires-Dist: protobug==1.0.0
13
14
  Requires-Dist: tzdata>=2024.1 ; sys_platform == 'win32'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bazaar-compute-node"
3
- version = "0.1.32"
3
+ version = "0.1.34"
4
4
  description = "Runtime-agnostic computer node daemon for agents and channels."
5
5
  readme = "README.md"
6
6
  license = "AGPL-3.0-only"
@@ -11,6 +11,7 @@ dependencies = [
11
11
  "aiosqlite>=0.20.0",
12
12
  "cryptography>=45.0.0",
13
13
  "jinja2>=3.1.6",
14
+ "packaging>=25.0",
14
15
  "pydantic>=2.0.0",
15
16
  "protobug==1.0.0",
16
17
  "tzdata>=2024.1; sys_platform == 'win32'",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "bazaar-compute-node"
3
- version = "0.1.32"
3
+ version = "0.1.34"
4
4
  description = "Runtime-agnostic computer node daemon for agents and channels."
5
5
  readme = "README.md"
6
6
  license = "AGPL-3.0-only"
@@ -11,6 +11,7 @@ dependencies = [
11
11
  "aiosqlite>=0.20.0",
12
12
  "cryptography>=45.0.0",
13
13
  "jinja2>=3.1.6",
14
+ "packaging>=25.0",
14
15
  "pydantic>=2.0.0",
15
16
  "protobug==1.0.0",
16
17
  "tzdata>=2024.1; sys_platform == 'win32'",
@@ -0,0 +1,4 @@
1
+ from importlib.metadata import version
2
+
3
+ __distribution__ = "bazaar-compute-node"
4
+ __version__ = version(__distribution__)
@@ -9,12 +9,17 @@ import re
9
9
  import secrets
10
10
  from collections.abc import Callable, Mapping, Sequence
11
11
  from dataclasses import dataclass
12
+ from functools import partial
12
13
  from pathlib import Path
13
14
 
14
15
  from ..core.channel import AgentScopedChannel, ChannelContext, IChannel
15
16
  from ..core.concurrency import ISessionConcurrency, SessionLockRegistry
16
17
  from ..core.lifecycle import TimeoutBudget
17
- from ..core.models import InboundAttachment, Message, RuntimeSession
18
+ from ..core.models import (
19
+ InboundAttachment,
20
+ Message,
21
+ RuntimeSession,
22
+ )
18
23
  from ..core.observability import IAudit
19
24
  from ..core.orchestration import SessionOrchestrator
20
25
  from ..core.orchestration.reminder_command import ReminderCommandService
@@ -28,6 +33,7 @@ from .command import CommandDispatchError
28
33
  from .config import AgentConfiguration
29
34
  from .registry import AgentAdapterFactories
30
35
  from .resource_dispatch import CommandDispatcher
36
+ from .upgrade import UpgradeService
31
37
  from .wrapper import install_bcc_wrapper, remove_bcc_wrapper
32
38
 
33
39
  CommandRecord = tuple[str, tuple[str, ...]]
@@ -73,6 +79,8 @@ class AgentApplication:
73
79
  endpoint: Callable[[], str],
74
80
  timeout_budget: TimeoutBudget,
75
81
  translator: Translator,
82
+ upgrade_service: UpgradeService,
83
+ upgrade_notice: Callable[[], tuple[str, str] | None] = lambda: None,
76
84
  ) -> None:
77
85
  self.configuration = configuration
78
86
  self.agent_id = configuration.id
@@ -89,7 +97,7 @@ class AgentApplication:
89
97
  self._concurrency = SessionLockRegistry()
90
98
  self._started = False
91
99
  self._stopping = False
92
- self._runtime_environment_include = configuration.runtime.env_include
100
+ self._runtime_configurations = configuration.runtimes
93
101
  self._logger = logging.getLogger("bazaar_compute_node.application.agent")
94
102
  self._attachment_materializer = AttachmentMaterializer(
95
103
  self.workspace_path,
@@ -106,54 +114,64 @@ class AgentApplication:
106
114
  )
107
115
  )
108
116
  self.channel: IChannel = AgentScopedChannel(self.agent_id, provider_channel)
109
- runtime_options: dict[str, str] = {
110
- key: value
111
- for key, value in configuration.runtime.options.items()
112
- if isinstance(value, str)
113
- }
114
- if configuration.runtime.model is not None:
115
- runtime_options["model"] = configuration.runtime.model
116
- if configuration.runtime.effort is not None:
117
- runtime_options["effort"] = configuration.runtime.effort
118
- self._runtime_context = RuntimeCommandContext(
119
- run_command=self._run_runtime_command,
120
- environment_for_session=self._runtime_environment,
121
- agent_id=self.agent_id,
122
- agent_name=self.name,
123
- bot_name=self._bot_name,
124
- runtime_options=runtime_options,
125
- sandbox_mode=configuration.runtime.sandbox_mode,
126
- network_access=configuration.runtime.network_access,
127
- startup_timeout_seconds=timeout_budget.startup_seconds,
128
- )
129
- self.runtime: IRuntime = factories.runtime(self._runtime_context)
130
- idle_timeout_seconds = configuration.runtime.idle_timeout_seconds
117
+ runtime_contexts: list[RuntimeCommandContext] = []
118
+ runtimes: list[IRuntime] = []
119
+ for index, runtime_configuration in enumerate(configuration.runtimes):
120
+ runtime_options: dict[str, str] = {
121
+ key: value
122
+ for key, value in runtime_configuration.options.items()
123
+ if isinstance(value, str)
124
+ }
125
+ if runtime_configuration.model is not None:
126
+ runtime_options["model"] = runtime_configuration.model
127
+ if runtime_configuration.effort is not None:
128
+ runtime_options["effort"] = runtime_configuration.effort
129
+ context = RuntimeCommandContext(
130
+ run_command=self._run_runtime_command,
131
+ # the context belongs to one instance, so the index it builds
132
+ # the child environment for is fixed here
133
+ environment_for_session=partial(self._runtime_environment, index),
134
+ agent_id=self.agent_id,
135
+ agent_name=self.name,
136
+ bot_name=self._bot_name,
137
+ runtime_options=runtime_options,
138
+ sandbox_mode=runtime_configuration.sandbox_mode,
139
+ network_access=runtime_configuration.network_access,
140
+ startup_timeout_seconds=timeout_budget.startup_seconds,
141
+ )
142
+ runtime_contexts.append(context)
143
+ runtimes.append(factories.runtimes[runtime_configuration.kind](context))
144
+ idle_timeout_seconds = configuration.idle_timeout_seconds
131
145
  if (
132
146
  isinstance(idle_timeout_seconds, bool)
133
147
  or not isinstance(idle_timeout_seconds, int | float)
134
148
  or not math.isfinite(idle_timeout_seconds)
135
149
  ):
136
- raise ValueError("runtime idle timeout must be a finite number")
150
+ raise ValueError("agent idle timeout must be a finite number")
137
151
  if (
138
152
  idle_timeout_seconds > 0
139
153
  and idle_timeout_seconds * 1_000 > timer_wheel.maximum_delay_ms
140
154
  ):
141
- raise ValueError("runtime idle timeout exceeds the timer horizon")
142
- runtime_idle_timeout_ms = (
143
- math.ceil(idle_timeout_seconds * 1_000) if idle_timeout_seconds > 0 else 0
144
- )
155
+ raise ValueError("agent idle timeout exceeds the timer horizon")
156
+ self._runtime_contexts = tuple(runtime_contexts)
157
+ self.runtimes: tuple[IRuntime, ...] = tuple(runtimes)
145
158
  self.orchestrator = SessionOrchestrator(
146
159
  agent_id=self.agent_id,
147
160
  channel=self.channel,
148
- runtime=self.runtime,
161
+ runtimes=self.runtimes,
149
162
  storage=self.storage,
150
163
  audit=self.audit,
151
164
  timeout_budget=self.timeout_budget,
152
165
  timer_wheel=self.timer_wheel,
153
- runtime_idle_timeout_ms=runtime_idle_timeout_ms,
166
+ runtime_idle_timeout_ms=(
167
+ math.ceil(idle_timeout_seconds * 1_000)
168
+ if idle_timeout_seconds > 0
169
+ else 0
170
+ ),
154
171
  workspace=self.workspace_path,
155
172
  translator=self.translator,
156
173
  error_feedback_detail=self._error_feedback_detail,
174
+ upgrade_notice=upgrade_notice,
157
175
  concurrency=self._concurrency,
158
176
  )
159
177
  self.reminder_service = ReminderCommandService(
@@ -161,21 +179,12 @@ class AgentApplication:
161
179
  concurrency=reminder_concurrency,
162
180
  poke=reminder_poke,
163
181
  )
164
- self._provider_control_handler = (
165
- factories.control(self._adapter_context())
166
- if factories.control is not None
167
- else None
168
- )
169
182
  self.command_dispatcher = CommandDispatcher(
170
183
  self.orchestrator.command_service,
171
184
  reminder_service=self.reminder_service,
172
185
  timeout_budget=self.timeout_budget,
173
- control_handler=(
174
- self._handle_control
175
- if self._provider_control_handler is not None
176
- else None
177
- ),
178
186
  session_binding_validator=self._validate_session_binding,
187
+ upgrade_service=upgrade_service,
179
188
  )
180
189
 
181
190
  @property
@@ -275,7 +284,7 @@ class AgentApplication:
275
284
  "name": self.name,
276
285
  "status": "started" if self.started else "stopped",
277
286
  "channel": self.channel.name,
278
- "runtime": self.runtime.name,
287
+ "runtimes": tuple(runtime.name for runtime in self.runtimes),
279
288
  "channel_health": dict(self.channel.health),
280
289
  "orchestrator_health": self.orchestrator.health,
281
290
  }
@@ -303,37 +312,6 @@ class AgentApplication:
303
312
  async def _referenced_attachment_paths(self) -> set[str]:
304
313
  return set(await self.storage.list_ready_attachment_paths())
305
314
 
306
- def _adapter_context(self) -> Mapping[str, object]:
307
- return {
308
- "agent_id": self.agent_id,
309
- "agent_name": self.name,
310
- "channel": self.channel,
311
- "runtime": self.runtime,
312
- "storage": self.storage,
313
- "audit": self.audit,
314
- "command_log": self.command_log,
315
- "is_started": lambda: self._started,
316
- }
317
-
318
- async def _handle_control(
319
- self,
320
- request: Mapping[str, object],
321
- ) -> Mapping[str, object]:
322
- session_id = request.get("session_id")
323
- if not isinstance(session_id, str) or not session_id:
324
- raise CommandDispatchError(
325
- "SESSION_REQUIRED",
326
- "session_id must be a non-empty string",
327
- )
328
- await self._validate_session_binding(session_id, request)
329
- handler = self._provider_control_handler
330
- if handler is None:
331
- raise CommandDispatchError(
332
- "INVALID_COMMAND",
333
- "control operation is not supported",
334
- )
335
- return await handler(request)
336
-
337
315
  async def _validate_session_binding(
338
316
  self,
339
317
  session_id: str,
@@ -374,19 +352,26 @@ class AgentApplication:
374
352
  "session capability is invalid",
375
353
  )
376
354
 
377
- def _runtime_environment(self, session: RuntimeSession) -> Mapping[str, str]:
355
+ def _runtime_environment(
356
+ self,
357
+ runtime_index: int,
358
+ session: RuntimeSession,
359
+ ) -> Mapping[str, str]:
378
360
  runtime_session = self.orchestrator.runtime_session(session.bcn_session_id)
379
361
  if runtime_session is None or runtime_session.id != session.id:
380
362
  raise RuntimeError("runtime session is not the current live binding")
381
363
  return self._build_command_environment(
382
364
  session.bcn_session_id,
383
365
  session.id,
366
+ runtime_index=runtime_index,
384
367
  )
385
368
 
386
369
  def _build_command_environment(
387
370
  self,
388
371
  session_id: str,
389
372
  runtime_session_id: str,
373
+ *,
374
+ runtime_index: int,
390
375
  ) -> dict[str, str]:
391
376
  if not session_id:
392
377
  raise ValueError("session_id must be a non-empty string")
@@ -395,14 +380,15 @@ class AgentApplication:
395
380
  wrapper_path = self._wrapper_path
396
381
  if wrapper_path is None:
397
382
  raise RuntimeError("bcc wrapper is not installed")
383
+ environment_bindings = self._runtime_configurations[runtime_index].env
398
384
  binding = self._session_capabilities.get(session_id)
399
385
  if binding is None or binding.runtime_session_id != runtime_session_id:
400
386
  capability = secrets.token_urlsafe(32)
401
387
  token_values = [capability]
402
- for name in self._runtime_environment_include:
388
+ for name, source_name in environment_bindings.items():
403
389
  if name != "TOKEN" and not name.endswith("_TOKEN"):
404
390
  continue
405
- value = os.environ.get(name)
391
+ value = os.environ.get(source_name)
406
392
  if value and value not in token_values:
407
393
  token_values.append(value)
408
394
  binding = _SessionCapabilityBinding(
@@ -414,19 +400,32 @@ class AgentApplication:
414
400
  )
415
401
  self._session_capabilities[session_id] = binding
416
402
  allowed = set(_PLATFORM_ENVIRONMENT)
417
- for name in self.runtime.environment_variable_names():
418
- if not _ENVIRONMENT_NAME.fullmatch(name):
419
- raise ValueError(f"runtime environment name is invalid: {name}")
420
- allowed.add(name)
421
- for name in self._runtime_environment_include:
403
+ for name in self.runtimes[runtime_index].environment_variable_names():
422
404
  if not _ENVIRONMENT_NAME.fullmatch(name):
423
405
  raise ValueError(f"runtime environment name is invalid: {name}")
424
- if name not in os.environ:
425
- raise ValueError(f"runtime environment variable is missing: {name}")
426
406
  allowed.add(name)
427
407
  environment = {
428
408
  name: os.environ[name] for name in sorted(allowed) if os.environ.get(name)
429
409
  }
410
+ bound: dict[str, str] = {}
411
+ for name, source_name in sorted(environment_bindings.items()):
412
+ for candidate in (name, source_name):
413
+ if not _ENVIRONMENT_NAME.fullmatch(candidate):
414
+ raise ValueError(
415
+ f"runtime environment name is invalid: {candidate}"
416
+ )
417
+ if source_name not in os.environ:
418
+ raise ValueError(
419
+ f"runtime environment variable is missing: {source_name}"
420
+ )
421
+ bound[name] = os.environ[source_name]
422
+ for source_name in environment_bindings.values():
423
+ # the credential reaches the child only under the name it asked for,
424
+ # never under the node's own name for it, unless the child asked for
425
+ # that name as well
426
+ if source_name not in environment_bindings:
427
+ environment.pop(source_name, None)
428
+ environment.update(bound)
430
429
  environment["PATH"] = os.pathsep.join(
431
430
  (str(wrapper_path.parent), environment.get("PATH", os.defpath))
432
431
  )
@@ -479,6 +478,7 @@ class AgentApplication:
479
478
  environment = self._build_command_environment(
480
479
  session_id,
481
480
  runtime_session.id,
481
+ runtime_index=runtime_session.runtime_index,
482
482
  )
483
483
  process = await asyncio.create_subprocess_exec(
484
484
  str(wrapper_path),
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import argparse
4
+ import sys
4
5
  import tomllib
5
6
  from dataclasses import replace
6
7
  from types import MappingProxyType
@@ -84,25 +85,38 @@ def run_agent_command(
84
85
  for agent in configuration.agents:
85
86
  print(
86
87
  f"id={agent.id} name={agent.name} "
87
- f"channel={agent.channel.kind} runtime={agent.runtime.kind}",
88
+ f"channel={agent.channel.kind} runtime={_runtime_kinds(agent)}",
88
89
  flush=True,
89
90
  )
90
91
  return 0
91
92
 
92
93
  if command == "add":
94
+ agent_values: dict[str, object] = {}
93
95
  channel_options: dict[str, object] = {}
94
96
  runtime_values: dict[str, object] = {}
97
+ runtime_env: dict[str, str] = {}
95
98
  seen: set[tuple[str, str]] = set()
96
99
  for scope, key, value in args.agent_options:
100
+ # runtime.env accumulates one name per --set; a repeated name is
101
+ # simply overwritten, the same as a hand-edited config.toml would be
102
+ if (scope, key) == ("runtime", "env"):
103
+ runtime_env.update(value)
104
+ continue
97
105
  identity = (scope, key)
98
106
  if identity in seen:
99
107
  parser.error(f"duplicate --set option: {scope}.{key}")
100
108
  seen.add(identity)
101
- if scope == "channel":
109
+ if scope == "agent":
110
+ agent_values[key] = value
111
+ elif scope == "channel":
102
112
  channel_options[key] = value
103
113
  else:
104
114
  runtime_values[key] = value
105
115
 
116
+ idle_timeout = agent_values.pop("idle_timeout", 0)
117
+ if isinstance(idle_timeout, bool) or not isinstance(idle_timeout, int | float):
118
+ parser.error("agent.idle_timeout must be a number")
119
+
106
120
  model = runtime_values.pop("model", None)
107
121
  effort = runtime_values.pop("effort", None)
108
122
  raw_sandbox_mode = runtime_values.pop(
@@ -119,16 +133,6 @@ def run_agent_command(
119
133
  network_access = runtime_values.pop("network_access", True)
120
134
  if not isinstance(network_access, bool):
121
135
  parser.error("runtime.network_access must be a boolean")
122
- idle_timeout = runtime_values.pop("idle_timeout", 0)
123
- if isinstance(idle_timeout, bool) or not isinstance(idle_timeout, int | float):
124
- parser.error("runtime.idle_timeout must be a number")
125
- raw_env_include = runtime_values.pop("env_include", [])
126
- if not isinstance(raw_env_include, list) or any(
127
- not isinstance(item, str) or not item for item in raw_env_include
128
- ):
129
- parser.error("runtime.env_include must be an array of non-empty text")
130
- if len(set(raw_env_include)) != len(raw_env_include):
131
- parser.error("runtime.env_include cannot contain duplicates")
132
136
  if model is not None and not isinstance(model, str):
133
137
  parser.error("runtime.model must be text")
134
138
  if effort is not None and not isinstance(effort, str):
@@ -142,16 +146,18 @@ def run_agent_command(
142
146
  kind=args.channel,
143
147
  options=MappingProxyType(channel_options),
144
148
  ),
145
- runtime=RuntimeConfiguration(
146
- kind=args.runtime,
147
- model=model,
148
- effort=effort,
149
- sandbox_mode=sandbox_mode,
150
- network_access=network_access,
151
- idle_timeout_seconds=idle_timeout,
152
- env_include=tuple(raw_env_include),
153
- options=MappingProxyType(runtime_values),
149
+ runtimes=(
150
+ RuntimeConfiguration(
151
+ kind=args.runtime,
152
+ model=model,
153
+ effort=effort,
154
+ sandbox_mode=sandbox_mode,
155
+ network_access=network_access,
156
+ env=MappingProxyType(runtime_env),
157
+ options=MappingProxyType(runtime_values),
158
+ ),
154
159
  ),
160
+ idle_timeout_seconds=idle_timeout,
155
161
  )
156
162
  updated = replace(
157
163
  configuration,
@@ -162,7 +168,7 @@ def run_agent_command(
162
168
  parser.error(str(error))
163
169
  print(
164
170
  f"Agent added id={agent.id} name={agent.name} "
165
- f"channel={agent.channel.kind} runtime={agent.runtime.kind}",
171
+ f"channel={agent.channel.kind} runtime={_runtime_kinds(agent)}",
166
172
  flush=True,
167
173
  )
168
174
  print("Run `bcn restart` to apply.", flush=True)
@@ -204,23 +210,60 @@ def _agent_option(value: str) -> tuple[str, str, object]:
204
210
  if path != path.strip():
205
211
  raise argparse.ArgumentTypeError("--set option path cannot contain whitespace")
206
212
  scope, dot, key = path.partition(".")
207
- if not dot or scope not in {"channel", "runtime"} or not key:
213
+ if not dot or scope not in {"agent", "channel", "runtime"} or not key:
208
214
  raise argparse.ArgumentTypeError(
209
- "--set path must start with channel. or runtime."
215
+ "--set path must start with agent., channel. or runtime."
210
216
  )
211
217
  if key != key.strip():
212
218
  raise argparse.ArgumentTypeError(
213
219
  "--set option key cannot contain edge whitespace"
214
220
  )
215
- if key == "kind":
221
+ if key == "kind" and scope != "agent":
216
222
  raise argparse.ArgumentTypeError(
217
223
  f"{scope}.kind must be provided with --{scope}"
218
224
  )
225
+ if scope == "runtime" and key == "env":
226
+ return scope, key, _env_pair(raw_value)
219
227
  try:
220
228
  parsed = tomllib.loads(f"value = {raw_value}")["value"]
221
229
  except tomllib.TOMLDecodeError:
222
230
  parsed = raw_value
231
+ if scope == "runtime" and key == "env_include":
232
+ return scope, "env", _env_from_deprecated_include(parsed)
223
233
  return scope, key, parsed
224
234
 
225
235
 
236
+ def _env_pair(value: str) -> dict[str, str]:
237
+ name, separator, source = value.partition("=")
238
+ if not separator or not name or not source:
239
+ raise argparse.ArgumentTypeError(
240
+ "runtime.env must use <name>=<source>, for example "
241
+ "--set runtime.env=CODEX_HOME=BCN_CODEX_HOME_WORK"
242
+ )
243
+ return {name: source}
244
+
245
+
246
+ def _env_from_deprecated_include(value: object) -> dict[str, str]:
247
+ if not isinstance(value, list) or any(
248
+ not isinstance(item, str) or not item for item in value
249
+ ):
250
+ raise argparse.ArgumentTypeError(
251
+ "runtime.env_include must be an array of non-empty text"
252
+ )
253
+ if len(set(value)) != len(value):
254
+ raise argparse.ArgumentTypeError(
255
+ "runtime.env_include cannot contain duplicates"
256
+ )
257
+ print(
258
+ create_translator(None).text("cli.agent.env_include_deprecated"),
259
+ file=sys.stderr,
260
+ flush=True,
261
+ )
262
+ return {name: name for name in value}
263
+
264
+
265
+ def _runtime_kinds(agent: AgentConfiguration) -> str:
266
+ return ",".join(runtime.kind for runtime in agent.runtimes)
267
+
268
+
226
269
  __all__ = ["build_agent_parser", "run_agent_command"]