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.
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/PKG-INFO +1 -1
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/pyproject.toml +1 -1
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/pyproject.toml.orig +1 -1
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/process.py +72 -3
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/runtime.py +19 -30
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/process.py +100 -23
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/runtime.py +10 -84
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/codec.py +7 -4
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/registry.py +2 -0
- bazaar_compute_node-0.2.0rc5/src/bazaar_compute_node/contrib/sqlite/migrations/v27_name_dms_by_the_peer_id.py +160 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/messages.py +11 -1
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/storage.py +1 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/channel.py +11 -14
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/outbound.py +45 -2
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/channel.py +10 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/command.py +259 -95
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/delivery.py +15 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/orchestrator.py +43 -109
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/outcomes.py +1 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/runtime.py +1 -8
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/storage.py +24 -17
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/LICENSE +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/README.md +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/agent.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/agent_management.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/application.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/attachments.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/command.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/config.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/registry.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/resource_dispatch.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/system_service.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/transport.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/upgrade.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/usage.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/version_check.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/windows_pipe.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/app/wrapper.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/bcc.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cli.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/_client.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/_format.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/inbox.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/message.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/node.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/reminder.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcc/thread.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/_options.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/_runner.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/agent.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/node.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/cmd/bcn/service.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/approval.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/client.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/events.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/plugin.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/claude/protocol.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/approval.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/client.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/events.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/plugin.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/codex/protocol.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/api.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/approval.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/attachments.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/channel.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/frame.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/identity.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/outbound.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/plugin.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/lark/transport.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/logging/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/logging/audit.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/logging/plugin.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/database.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/executor.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/migrations/model.py +0 -0
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {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
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/plugin.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/reminder_codec.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/base.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/facade.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/reminders.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/sqlite/repository/sessions.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/api.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/approval.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/attachments.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/identity.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/markdown.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/telegram/plugin.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/wecom/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/wecom/channel.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/wecom/outbound.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/contrib/wecom/plugin.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/actor.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/agent.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/approval.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/audit.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/client.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/command.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/concurrency.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/correlation.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/inbox.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/instruction.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/lifecycle.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/entities.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/events.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/reminder.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/reminder_owner.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/models/states.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/observability.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/error_feedback.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/reminder.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/reminder_command.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/services.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/turn.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/orchestration/upgrade_notice.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/paths.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/reminder.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/reminder_schedule.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/restart.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/timerwheel.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/clock.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/line_reader.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/markdown.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/sanitization.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/core/utils/text.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/i18n/__init__.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/i18n/catalog.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/rendering.py +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/approval_no_person.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/check.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/error.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/inbox_check.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/read.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/reminder_list.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/reminder_mutation.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/reminder_schedule.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/unfollow.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/upgrade.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/bcc/version.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/attachment_suffix.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/check_message.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/freshness_hold.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/read_message.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/send_result.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/command/sender.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/developer_instructions.md +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/inbox_notice.tpl +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/locales/en.toml +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/locales/zh-CN.toml +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/launchd.plist +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/launchd.sh +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/systemd.service +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/windows.ps1 +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/windows.vbs +0 -0
- {bazaar_compute_node-0.2.0rc4 → bazaar_compute_node-0.2.0rc5}/src/bazaar_compute_node/resources/system_service/windows.xml +0 -0
|
@@ -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.
|
|
151
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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]) ->
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
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.
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
190
|
+
await self._wait_for_process(process, terminate_deadline)
|
|
183
191
|
except TimeoutError:
|
|
184
192
|
_kill_process(process)
|
|
185
|
-
|
|
186
|
-
|
|
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
|
|
9
|
-
from dataclasses import dataclass,
|
|
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
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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
|
-
|
|
540
|
-
|
|
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
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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
|
|