@team-agent/installer 0.5.60 → 0.5.62
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.
- package/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +49 -3
- package/crates/team-agent/src/cli/attach_app_server_leader.rs +1 -0
- package/crates/team-agent/src/cli/diagnose.rs +184 -0
- package/crates/team-agent/src/cli/emit.rs +104 -21
- package/crates/team-agent/src/cli/helpers.rs +1 -0
- package/crates/team-agent/src/cli/leader.rs +14 -2
- package/crates/team-agent/src/cli/leaders.rs +2 -0
- package/crates/team-agent/src/cli/mod.rs +296 -8
- package/crates/team-agent/src/cli/named_address.rs +26 -2
- package/crates/team-agent/src/cli/profile.rs +2 -1
- package/crates/team-agent/src/cli/send/coordinator.rs +1 -0
- package/crates/team-agent/src/cli/send/mailbox.rs +3 -0
- package/crates/team-agent/src/cli/send/persist.rs +1 -0
- package/crates/team-agent/src/cli/send/presentation.rs +3 -0
- package/crates/team-agent/src/cli/send/resolve.rs +206 -1
- package/crates/team-agent/src/cli/send.rs +2 -1
- package/crates/team-agent/src/cli/spec.rs +5 -1
- package/crates/team-agent/src/cli/status.rs +2 -1
- package/crates/team-agent/src/cli/status_port/compact.rs +1 -0
- package/crates/team-agent/src/cli/status_port/format.rs +1 -0
- package/crates/team-agent/src/cli/status_port/inbox.rs +1 -0
- package/crates/team-agent/src/cli/status_port/store.rs +7 -3
- package/crates/team-agent/src/cli/tests/named_address.rs +65 -0
- package/crates/team-agent/src/cli/tests/verb_profile.rs +38 -0
- package/crates/team-agent/src/cli/types.rs +36 -2
- package/crates/team-agent/src/communication_mode/mod.rs +54 -0
- package/crates/team-agent/src/compiler/tests.rs +5 -5
- package/crates/team-agent/src/compiler.rs +54 -1
- package/crates/team-agent/src/conpty/backend.rs +1 -0
- package/crates/team-agent/src/conpty/mod.rs +1 -0
- package/crates/team-agent/src/coordinator/backoff.rs +5 -8
- package/crates/team-agent/src/coordinator/conpty_shim.rs +3 -2
- package/crates/team-agent/src/coordinator/health.rs +1 -0
- package/crates/team-agent/src/coordinator/mod.rs +2 -2
- package/crates/team-agent/src/coordinator/orphan.rs +4 -116
- package/crates/team-agent/src/coordinator/runtime_detectors.rs +1 -0
- package/crates/team-agent/src/coordinator/runtime_observation.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +6 -5
- package/crates/team-agent/src/coordinator/steps/delivery.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/health_sync.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/mod.rs +2 -0
- package/crates/team-agent/src/coordinator/steps/persist.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +1 -0
- package/crates/team-agent/src/coordinator/steps/session_gate.rs +1 -0
- package/crates/team-agent/src/coordinator/tests/abnormal.rs +0 -174
- package/crates/team-agent/src/coordinator/tests/api_error_recovery.rs +0 -9
- package/crates/team-agent/src/coordinator/tests/basics.rs +0 -184
- package/crates/team-agent/src/coordinator/tests/mod.rs +2 -17
- package/crates/team-agent/src/coordinator/tests/tick_core.rs +0 -42
- package/crates/team-agent/src/coordinator/tick.rs +24 -28
- package/crates/team-agent/src/coordinator/types.rs +3 -176
- package/crates/team-agent/src/db/agent_health_capture.rs +1 -0
- package/crates/team-agent/src/db/message_store.rs +47 -2
- package/crates/team-agent/src/db/migration.rs +5 -4
- package/crates/team-agent/src/db/mod.rs +1 -0
- package/crates/team-agent/src/db/schema.rs +1 -0
- package/crates/team-agent/src/diagnose/comms.rs +2 -1
- package/crates/team-agent/src/diagnose/mod.rs +1 -0
- package/crates/team-agent/src/diagnose/orphans.rs +1 -0
- package/crates/team-agent/src/fake_worker.rs +21 -1
- package/crates/team-agent/src/layout/manager.rs +3 -7
- package/crates/team-agent/src/layout/mod.rs +2 -2
- package/crates/team-agent/src/layout/overlay.rs +6 -1
- package/crates/team-agent/src/layout/placement.rs +1 -0
- package/crates/team-agent/src/layout/recovery.rs +3 -0
- package/crates/team-agent/src/layout/runtime_sessions.rs +8 -3
- package/crates/team-agent/src/layout/sessions.rs +8 -1
- package/crates/team-agent/src/layout/tmux_endpoint.rs +3 -0
- package/crates/team-agent/src/layout/worker_env.rs +3 -0
- package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
- package/crates/team-agent/src/leader/helpers.rs +1 -0
- package/crates/team-agent/src/leader/incident.rs +1 -0
- package/crates/team-agent/src/leader/lease.rs +27 -22
- package/crates/team-agent/src/leader/mod.rs +2 -3
- package/crates/team-agent/src/leader/owner_bind.rs +13 -3
- package/crates/team-agent/src/leader/provider_attribution.rs +1 -0
- package/crates/team-agent/src/leader/rediscover.rs +4 -17
- package/crates/team-agent/src/leader/registry.rs +3 -15
- package/crates/team-agent/src/leader/start.rs +1072 -186
- package/crates/team-agent/src/leader/takeover.rs +10 -232
- package/crates/team-agent/src/leader/tests/claim_leader_mailbox_flush_contract.rs +544 -0
- package/crates/team-agent/src/leader/tests/historical_inventory_upgrade_gate_red.rs +624 -0
- package/crates/team-agent/src/leader/tests/identity.rs +71 -59
- package/crates/team-agent/src/leader/tests/identity_session_names.rs +42 -0
- package/crates/team-agent/src/leader/tests/idle.rs +0 -193
- package/crates/team-agent/src/leader/tests/lease_api.rs +0 -45
- package/crates/team-agent/src/leader/tests/mod.rs +4 -41
- package/crates/team-agent/src/leader/tests/rehomed_env.rs +83 -0
- package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1273 -0
- package/crates/team-agent/src/leader/tests/terminal_and_replay_vs_rerender_invariants_red.rs +417 -0
- package/crates/team-agent/src/leader/tests/wake_start_owner.rs +22 -103
- package/crates/team-agent/src/leader/types.rs +1 -28
- package/crates/team-agent/src/lib.rs +7 -0
- package/crates/team-agent/src/lifecycle/display.rs +7 -1
- package/crates/team-agent/src/lifecycle/helpers.rs +3 -1
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +2 -2
- package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch/plan.rs +2 -2
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +4 -26
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +0 -27
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +2 -28
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +4 -32
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +1 -0
- package/crates/team-agent/src/lifecycle/launch.rs +11 -12
- package/crates/team-agent/src/lifecycle/mod.rs +2 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +4 -4
- package/crates/team-agent/src/lifecycle/restart/common.rs +1 -1
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +2 -2
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +13 -5
- package/crates/team-agent/src/lifecycle/restart/remove.rs +1 -1
- package/crates/team-agent/src/lifecycle/restart/selection.rs +3 -3
- package/crates/team-agent/src/lifecycle/restart.rs +13 -11
- package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1007 -0
- package/crates/team-agent/src/lifecycle/tests/b0_legacy_snapshot_nonauthority_contract.rs +265 -0
- package/crates/team-agent/src/lifecycle/tests/b0_reader_hideone_audit_contract.rs +459 -0
- package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +849 -0
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +323 -0
- package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +423 -0
- package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +737 -0
- package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +1187 -0
- package/crates/team-agent/src/lifecycle/tests/codex_weak_window_attribution_red.rs +683 -0
- package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +394 -0
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +1856 -0
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +917 -0
- package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +481 -0
- package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +301 -0
- package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +516 -0
- package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +986 -0
- package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +651 -0
- package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +2 -0
- package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +332 -0
- package/crates/team-agent/src/lifecycle/tests/realmachine_clusters_1_6_red.rs +846 -0
- package/crates/team-agent/src/lifecycle/tests/realmachine_residual_g1_g4_red.rs +648 -0
- package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +910 -0
- package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +630 -0
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +1083 -0
- package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +1677 -0
- package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +410 -0
- package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +428 -0
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +1032 -0
- package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +869 -0
- package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1249 -0
- package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +342 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +542 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1103 -0
- package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1276 -0
- package/crates/team-agent/src/lifecycle/tests/team_key_retirement_roster_red.rs +145 -0
- package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +603 -0
- package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +837 -0
- package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +928 -0
- package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +951 -0
- package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +327 -0
- package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +760 -0
- package/crates/team-agent/src/lifecycle/tests.rs +59 -0
- package/crates/team-agent/src/lifecycle/types.rs +0 -9
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +29 -11
- package/crates/team-agent/src/mcp_server/helpers.rs +1 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/mod.rs +1 -0
- package/crates/team-agent/src/mcp_server/lifecycle_tools/state_status.rs +1 -0
- package/crates/team-agent/src/mcp_server/mod.rs +1 -0
- package/crates/team-agent/src/mcp_server/normalize.rs +5 -3
- package/crates/team-agent/src/mcp_server/tests/send.rs +26 -0
- package/crates/team-agent/src/mcp_server/tests/wire.rs +1 -1
- package/crates/team-agent/src/mcp_server/tools.rs +101 -66
- package/crates/team-agent/src/mcp_server/types.rs +6 -18
- package/crates/team-agent/src/mcp_server/wire.rs +32 -26
- package/crates/team-agent/src/messaging/activity.rs +1 -0
- package/crates/team-agent/src/messaging/address.rs +1 -0
- package/crates/team-agent/src/messaging/delivery.rs +109 -41
- package/crates/team-agent/src/messaging/helpers.rs +2 -1
- package/crates/team-agent/src/messaging/leader_channel.rs +34 -10
- package/crates/team-agent/src/messaging/leader_receiver.rs +42 -24
- package/crates/team-agent/src/messaging/mod.rs +10 -14
- package/crates/team-agent/src/messaging/peers.rs +2 -0
- package/crates/team-agent/src/messaging/persist.rs +3 -1
- package/crates/team-agent/src/messaging/presentation.rs +111 -1
- package/crates/team-agent/src/messaging/results.rs +166 -17
- package/crates/team-agent/src/messaging/scheduler.rs +1 -0
- package/crates/team-agent/src/messaging/selftest.rs +1 -1
- package/crates/team-agent/src/messaging/send.rs +135 -89
- package/crates/team-agent/src/messaging/tests/leader_channel.rs +6 -6
- package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +187 -0
- package/crates/team-agent/src/messaging/tests/mod.rs +5 -0
- package/crates/team-agent/src/messaging/tests/runtime.rs +13 -6
- package/crates/team-agent/src/messaging/types.rs +7 -2
- package/crates/team-agent/src/messaging/watchers.rs +24 -13
- package/crates/team-agent/src/model/enums.rs +1 -0
- package/crates/team-agent/src/model/errors.rs +1 -0
- package/crates/team-agent/src/model/ids.rs +1 -0
- package/crates/team-agent/src/model/mod.rs +2 -0
- package/crates/team-agent/src/model/name_similarity.rs +1 -0
- package/crates/team-agent/src/model/pane_authority_refusal.rs +359 -0
- package/crates/team-agent/src/model/paths.rs +1 -0
- package/crates/team-agent/src/model/permissions.rs +3 -2
- package/crates/team-agent/src/model/routing.rs +1 -0
- package/crates/team-agent/src/model/spec.rs +17 -0
- package/crates/team-agent/src/model/task_graph.rs +1 -0
- package/crates/team-agent/src/model/yaml/tests.rs +1 -0
- package/crates/team-agent/src/model/yaml.rs +1 -0
- package/crates/team-agent/src/packaging/install.rs +9 -147
- package/crates/team-agent/src/packaging/migrate.rs +2 -0
- package/crates/team-agent/src/packaging/mod.rs +1 -0
- package/crates/team-agent/src/packaging/repair.rs +2 -0
- package/crates/team-agent/src/packaging/tests.rs +29 -218
- package/crates/team-agent/src/packaging/types.rs +8 -15
- package/crates/team-agent/src/platform/argv.rs +4 -0
- package/crates/team-agent/src/platform/errors.rs +10 -1
- package/crates/team-agent/src/platform/file_lock.rs +4 -157
- package/crates/team-agent/src/platform/mod.rs +0 -61
- package/crates/team-agent/src/platform/process.rs +1 -0
- package/crates/team-agent/src/provider/adapter.rs +1 -0
- package/crates/team-agent/src/provider/adapters/claude.rs +1 -0
- package/crates/team-agent/src/provider/adapters/claude_fork.rs +1 -0
- package/crates/team-agent/src/provider/adapters/codex.rs +1 -0
- package/crates/team-agent/src/provider/adapters/copilot.rs +1 -0
- package/crates/team-agent/src/provider/adapters/copilot_fork.rs +1 -0
- package/crates/team-agent/src/provider/adapters/fake.rs +1 -0
- package/crates/team-agent/src/provider/adapters/mod.rs +1 -0
- package/crates/team-agent/src/provider/approvals/mod.rs +1 -0
- package/crates/team-agent/src/provider/approvals/parsing.rs +2 -5
- package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +6 -5
- package/crates/team-agent/src/provider/classify.rs +1 -0
- package/crates/team-agent/src/provider/faults.rs +1 -26
- package/crates/team-agent/src/provider/helpers.rs +1 -0
- package/crates/team-agent/src/provider/mod.rs +1 -1
- package/crates/team-agent/src/provider/session/capture.rs +41 -22
- package/crates/team-agent/src/provider/session/context_fork/claude.rs +1 -0
- package/crates/team-agent/src/provider/session/context_fork/codex.rs +1 -0
- package/crates/team-agent/src/provider/session/context_fork/outcome.rs +1 -0
- package/crates/team-agent/src/provider/session/context_fork.rs +1 -0
- package/crates/team-agent/src/provider/session/mod.rs +2 -4
- package/crates/team-agent/src/provider/session/resume.rs +2 -209
- package/crates/team-agent/src/provider/session_scan/claude.rs +93 -3
- package/crates/team-agent/src/provider/session_scan/codex.rs +1 -0
- package/crates/team-agent/src/provider/session_scan/common.rs +24 -7
- package/crates/team-agent/src/provider/session_scan/copilot.rs +1 -0
- package/crates/team-agent/src/provider/session_scan.rs +6 -42
- package/crates/team-agent/src/provider/startup_prompt.rs +1 -0
- package/crates/team-agent/src/provider/types.rs +1 -0
- package/crates/team-agent/src/provider/wire.rs +1 -0
- package/crates/team-agent/src/state/identity.rs +16 -5
- package/crates/team-agent/src/state/identity_keys.rs +1 -0
- package/crates/team-agent/src/state/mod.rs +2 -0
- package/crates/team-agent/src/state/owner_gate.rs +5 -0
- package/crates/team-agent/src/state/ownership.rs +10 -4
- package/crates/team-agent/src/state/paths.rs +12 -0
- package/crates/team-agent/src/state/persist.rs +9 -3
- package/crates/team-agent/src/state/projection.rs +15 -2
- package/crates/team-agent/src/state/repository/intent.rs +1 -0
- package/crates/team-agent/src/state/repository/tests.rs +1 -0
- package/crates/team-agent/src/state/repository.rs +7 -0
- package/crates/team-agent/src/state/selector.rs +1 -0
- package/crates/team-agent/src/tmux_backend/tests.rs +39 -0
- package/crates/team-agent/src/tmux_backend.rs +63 -0
- package/crates/team-agent/src/topology.rs +3 -0
- package/crates/team-agent/src/transport.rs +15 -0
- package/package.json +4 -4
- package/skills/team-agent/command-coverage.json +379 -0
- package/crates/team-agent/src/leader/inject.rs +0 -33
- package/crates/team-agent/src/provider/command.rs +0 -80
|
@@ -189,7 +189,7 @@ fn front_matter_non_object_errors() {
|
|
|
189
189
|
// separators=(",",":"))` with the workspace path templated to __WS__.
|
|
190
190
|
// (team-agent-public v0.2.11, /tmp/probe_compiler.py.)
|
|
191
191
|
|
|
192
|
-
const BASE_NOPROFILE_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks and report result_envelope_v1.","file":null},"tools":["fs_read","fs_write","execute_bash","mcp_team"],"permission_mode":"restricted","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
|
|
192
|
+
const BASE_NOPROFILE_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks and report result_envelope_v1.","file":null},"tools":["fs_read","fs_write","execute_bash","mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
|
|
193
193
|
|
|
194
194
|
#[test]
|
|
195
195
|
fn compile_base_noprofile_matches_python_dict_order_and_values() {
|
|
@@ -259,7 +259,7 @@ tools:
|
|
|
259
259
|
Implement bounded tasks.
|
|
260
260
|
";
|
|
261
261
|
|
|
262
|
-
const RUNTIME_DEFAULTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.4","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"tools":["fs_read","mcp_team"],"permission_mode":"restricted","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"ghostty_window","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":true,"fast":true,"tick_interval_sec":1,"push_min_interval_sec":3,"stuck_timeout_sec":5},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
|
|
262
|
+
const RUNTIME_DEFAULTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.4","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"tools":["fs_read","mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"ghostty_window","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":true,"fast":true,"tick_interval_sec":1,"push_min_interval_sec":3,"stuck_timeout_sec":5},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
|
|
263
263
|
|
|
264
264
|
#[test]
|
|
265
265
|
fn compile_runtime_front_matter_defaults_match_python() {
|
|
@@ -299,7 +299,7 @@ tools:
|
|
|
299
299
|
Edit and defend the argument.
|
|
300
300
|
";
|
|
301
301
|
|
|
302
|
-
const ALIAS_JSON: &str = r#"{"version":1,"team":{"name":"debate-team","mode":"supervisor_worker","objective":"Compile thin role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"editor","role":"Editor and Defender","provider":"claude_code","model":"claude-sonnet-4-6","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Edit and defend the argument.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","preferred_for":["editor","Editor and Defender"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"editor","rules":[{"id":"route-editor","match":{"assignee":["editor"]},"assign_to":"editor","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-debate-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["editor"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"editor","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
|
|
302
|
+
const ALIAS_JSON: &str = r#"{"version":1,"team":{"name":"debate-team","mode":"supervisor_worker","objective":"Compile thin role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"editor","role":"Editor and Defender","provider":"claude_code","model":"claude-sonnet-4-6","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Edit and defend the argument.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["editor","Editor and Defender"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"editor","rules":[{"id":"route-editor","match":{"assignee":["editor"]},"assign_to":"editor","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-debate-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["editor"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"editor","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
|
|
303
303
|
|
|
304
304
|
#[test]
|
|
305
305
|
fn compile_provider_models_claude_code_falls_back_to_claude_alias() {
|
|
@@ -332,7 +332,7 @@ tools:
|
|
|
332
332
|
Implement bounded tasks.
|
|
333
333
|
";
|
|
334
334
|
|
|
335
|
-
const BUILTIN_JSON: &str = r#"{"version":1,"team":{"name":"default-model-team","mode":"supervisor_worker","objective":"Compile role docs without model fields.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-default-model-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
|
|
335
|
+
const BUILTIN_JSON: &str = r#"{"version":1,"team":{"name":"default-model-team","mode":"supervisor_worker","objective":"Compile role docs without model fields.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":null,"tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"implementer","role":"Implementation Engineer","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Implement bounded tasks.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["implementer","Implementation Engineer"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"implementer","rules":[{"id":"route-implementer","match":{"assignee":["implementer"]},"assign_to":"implementer","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"none","session_name":"team-default-model-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":1,"startup_order":["implementer"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"implementer","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
|
|
336
336
|
|
|
337
337
|
#[test]
|
|
338
338
|
fn compile_subscription_without_model_uses_builtin_provider_default() {
|
|
@@ -372,7 +372,7 @@ tools:
|
|
|
372
372
|
Bravo body.
|
|
373
373
|
";
|
|
374
374
|
|
|
375
|
-
const TWO_AGENTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"alpha","role":"Alpha Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Alpha body.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","preferred_for":["alpha","Alpha Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}},{"id":"bravo","role":"Bravo Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Bravo body.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","preferred_for":["bravo","Bravo Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"alpha","rules":[{"id":"route-alpha","match":{"assignee":["alpha"]},"assign_to":"alpha","priority":10},{"id":"route-bravo","match":{"assignee":["bravo"]},"assign_to":"bravo","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":2,"startup_order":["alpha","bravo"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"alpha","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
|
|
375
|
+
const TWO_AGENTS_JSON: &str = r#"{"version":1,"team":{"name":"doc-team","mode":"supervisor_worker","objective":"Compile role docs.","workspace":"__WS__"},"leader":{"id":"leader","role":"leader","provider":"codex","model":"gpt-5.5","tools":["fs_read","fs_list","mcp_team"],"context_policy":{"keep_user_thread":true,"receive_worker_outputs":"business_messages_and_short_summaries","max_worker_result_tokens":2000}},"agents":[{"id":"alpha","role":"Alpha Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Alpha body.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["alpha","Alpha Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}},{"id":"bravo","role":"Bravo Worker","provider":"codex","model":"gpt-5.5","auth_mode":"subscription","working_directory":"__WS__","system_prompt":{"inline":"Bravo body.","file":null},"tools":["mcp_team"],"permission_mode":"restricted","communication_mode":"leader_centric","preferred_for":["bravo","Bravo Worker"],"avoid_for":[],"output_contract":{"format":"result_envelope_v1","required_fields":["task_id","status","summary","artifacts"]}}],"routing":{"default_assignee":"alpha","rules":[{"id":"route-alpha","match":{"assignee":["alpha"]},"assign_to":"alpha","priority":10},{"id":"route-bravo","match":{"assignee":["bravo"]},"assign_to":"bravo","priority":10}]},"communication":{"protocol":"mcp_inbox","topology":"leader_centered","worker_to_worker":true,"ack_timeout_sec":60,"result_format":"result_envelope_v1","message_store":{"sqlite":".team/runtime/team.db","mirror_files":".team/messages"}},"runtime":{"backend":"tmux","display_backend":"adaptive","session_name":"team-doc-team","auto_launch":true,"require_user_approval_before_launch":true,"max_active_agents":2,"startup_order":["alpha","bravo"],"dangerous_auto_approve":false,"fast":false,"tick_interval_sec":2,"push_min_interval_sec":60,"stuck_timeout_sec":300},"context":{"state_file":"team_state.md","artifact_dir":".team/artifacts","log_dir":".team/logs","summarization":{"worker_full_logs":"retain_outside_leader_context","state_update":"after_each_result"}},"tasks":[{"id":"task_initial","title":"Initial document-driven team task","type":"implementation","assignee":"alpha","deps":[],"acceptance":["Worker reports valid result_envelope_v1"],"status":"pending","requires_tools":["mcp_team"],"files":[],"risk":"low"}]}"#;
|
|
376
376
|
|
|
377
377
|
#[test]
|
|
378
378
|
fn compile_two_agents_sorted_by_filename_with_routing_and_startup_order() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! step 6 · compiler — doc-driven team source → canonical `team.spec` dict.
|
|
2
3
|
//!
|
|
3
4
|
//! Truth source (READ-ONLY): `team-agent-public` @ v0.2.11, `team_agent/compiler.py`.
|
|
@@ -26,6 +27,7 @@
|
|
|
26
27
|
use std::fs;
|
|
27
28
|
use std::path::Path;
|
|
28
29
|
|
|
30
|
+
use crate::communication_mode::CommunicationMode;
|
|
29
31
|
use crate::model::enums::{Provider, ProviderEffort};
|
|
30
32
|
use crate::model::yaml::Value;
|
|
31
33
|
use crate::model::{paths, spec, yaml, ModelError};
|
|
@@ -133,6 +135,8 @@ pub fn compile_team(team_dir: &Path) -> Result<Value, ModelError> {
|
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
let (team_meta, team_body) = read_front_matter(&team_md)?;
|
|
138
|
+
let team_communication_mode =
|
|
139
|
+
communication_mode_field(&team_meta, &team_md)?.unwrap_or_default();
|
|
136
140
|
let mut role_paths = Vec::new();
|
|
137
141
|
if agents_dir.is_dir() {
|
|
138
142
|
for entry in fs::read_dir(&agents_dir)
|
|
@@ -170,7 +174,8 @@ pub fn compile_team(team_dir: &Path) -> Result<Value, ModelError> {
|
|
|
170
174
|
let mut agents = Vec::new();
|
|
171
175
|
let mut agent_ids = Vec::new();
|
|
172
176
|
for path in role_paths {
|
|
173
|
-
let compiled =
|
|
177
|
+
let compiled =
|
|
178
|
+
compile_role_agent_with_mode(&path, &team_meta, &workspace_s, team_communication_mode)?;
|
|
174
179
|
agent_ids.push(compiled.id);
|
|
175
180
|
agents.push(compiled.agent);
|
|
176
181
|
}
|
|
@@ -371,8 +376,21 @@ pub fn compile_role_agent(
|
|
|
371
376
|
role_path: &Path,
|
|
372
377
|
team_meta: &Value,
|
|
373
378
|
workspace_s: &str,
|
|
379
|
+
) -> Result<CompiledRole, ModelError> {
|
|
380
|
+
let team_communication_mode =
|
|
381
|
+
communication_mode_field(team_meta, role_path)?.unwrap_or_default();
|
|
382
|
+
compile_role_agent_with_mode(role_path, team_meta, workspace_s, team_communication_mode)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
fn compile_role_agent_with_mode(
|
|
386
|
+
role_path: &Path,
|
|
387
|
+
team_meta: &Value,
|
|
388
|
+
workspace_s: &str,
|
|
389
|
+
team_communication_mode: CommunicationMode,
|
|
374
390
|
) -> Result<CompiledRole, ModelError> {
|
|
375
391
|
let (meta, body) = read_front_matter(role_path)?;
|
|
392
|
+
let communication_mode =
|
|
393
|
+
communication_mode_field(&meta, role_path)?.unwrap_or(team_communication_mode);
|
|
376
394
|
let id = required_string(&meta, role_path, "name")?;
|
|
377
395
|
let role = required_string(&meta, role_path, "role")?;
|
|
378
396
|
let provider = required_string(&meta, role_path, "provider")?;
|
|
@@ -404,6 +422,10 @@ pub fn compile_role_agent(
|
|
|
404
422
|
),
|
|
405
423
|
("tools", list_str(tools)),
|
|
406
424
|
("permission_mode", Value::Str("restricted".to_string())),
|
|
425
|
+
(
|
|
426
|
+
"communication_mode",
|
|
427
|
+
Value::Str(communication_mode.as_str().to_string()),
|
|
428
|
+
),
|
|
407
429
|
("preferred_for", list_str(vec![id.clone(), role.clone()])),
|
|
408
430
|
("avoid_for", Value::List(Vec::new())),
|
|
409
431
|
(
|
|
@@ -469,6 +491,37 @@ pub fn compile_role_agent(
|
|
|
469
491
|
})
|
|
470
492
|
}
|
|
471
493
|
|
|
494
|
+
fn communication_mode_field(
|
|
495
|
+
meta: &Value,
|
|
496
|
+
path: &Path,
|
|
497
|
+
) -> Result<Option<CommunicationMode>, ModelError> {
|
|
498
|
+
let Some(raw) = meta.get("communication_mode") else {
|
|
499
|
+
return Ok(None);
|
|
500
|
+
};
|
|
501
|
+
let Some(value) = raw.as_str() else {
|
|
502
|
+
return Err(ModelError::Validation(format!(
|
|
503
|
+
"{}: unknown communication_mode (allowed: {})",
|
|
504
|
+
path.display(),
|
|
505
|
+
CommunicationMode::ALL
|
|
506
|
+
.iter()
|
|
507
|
+
.map(|mode| mode.as_str())
|
|
508
|
+
.collect::<Vec<_>>()
|
|
509
|
+
.join("|")
|
|
510
|
+
)));
|
|
511
|
+
};
|
|
512
|
+
CommunicationMode::parse(value).map(Some).ok_or_else(|| {
|
|
513
|
+
ModelError::Validation(format!(
|
|
514
|
+
"{}: unknown communication_mode '{value}' (allowed: {})",
|
|
515
|
+
path.display(),
|
|
516
|
+
CommunicationMode::ALL
|
|
517
|
+
.iter()
|
|
518
|
+
.map(|mode| mode.as_str())
|
|
519
|
+
.collect::<Vec<_>>()
|
|
520
|
+
.join("|")
|
|
521
|
+
))
|
|
522
|
+
})
|
|
523
|
+
}
|
|
524
|
+
|
|
472
525
|
fn map(items: Vec<(&str, Value)>) -> Value {
|
|
473
526
|
Value::Map(items.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
|
|
474
527
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! daemon 主循环面(`__main__.py`)—— 退避序列 + tick 间隔解析 + 子进程入口。
|
|
2
3
|
|
|
3
4
|
use thiserror::Error;
|
|
@@ -10,7 +11,7 @@ use crate::provider::ProviderAdapter;
|
|
|
10
11
|
use super::health::{coordinator_pid_path, write_coordinator_metadata};
|
|
11
12
|
use super::tick::{write_coordinator_heartbeat, TickError, TickReport, HEARTBEAT_STATUS_PANIC};
|
|
12
13
|
use super::types::{
|
|
13
|
-
|
|
14
|
+
MetadataSource, Pid, ProviderRegistry, WorkspacePath, BACKOFF_MAX_SEC,
|
|
14
15
|
DEFAULT_TICK_INTERVAL_SEC,
|
|
15
16
|
};
|
|
16
17
|
use super::Coordinator;
|
|
@@ -122,7 +123,7 @@ pub fn run_daemon(args: DaemonArgs) -> Result<(), DaemonError> {
|
|
|
122
123
|
run_daemon_with_coordinator_and_boot_tmux(&args, &coordinator, Some(tmux_metadata))
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
pub fn run_daemon_with_coordinator(
|
|
126
|
+
pub(crate) fn run_daemon_with_coordinator(
|
|
126
127
|
args: &DaemonArgs,
|
|
127
128
|
coordinator: &Coordinator,
|
|
128
129
|
) -> Result<(), DaemonError> {
|
|
@@ -519,14 +520,14 @@ fn current_ppid() -> u32 {
|
|
|
519
520
|
|
|
520
521
|
/// 计算 tick 间隔(`_tick_interval`,`__main__.py:104-115`)。读 spec `runtime.tick_interval_sec`,
|
|
521
522
|
/// 缺失/出错 → `DEFAULT_TICK_INTERVAL_SEC`;并确保 schema 存在(`MessageStore(workspace)`)。
|
|
522
|
-
pub fn resolve_tick_interval(workspace: &WorkspacePath) -> Result<f64, TickError> {
|
|
523
|
+
pub(super) fn resolve_tick_interval(workspace: &WorkspacePath) -> Result<f64, TickError> {
|
|
523
524
|
let _ = MessageStore::open(workspace.as_path())?;
|
|
524
525
|
Ok(DEFAULT_TICK_INTERVAL_SEC)
|
|
525
526
|
}
|
|
526
527
|
|
|
527
528
|
/// 退避序列(`__main__.py:65`):`min(interval * 2^min(failures-1, 5), 60.0)` → 5→10→20→40→60→60s。
|
|
528
529
|
/// unit test 锁死本序列(card §85)。**纯函数,无 I/O,可直接 impl 钉死**(但 ROUND-0 仍占位)。
|
|
529
|
-
pub fn backoff_sleep_sec(interval: f64, consecutive_failures: u32) -> f64 {
|
|
530
|
+
pub(super) fn backoff_sleep_sec(interval: f64, consecutive_failures: u32) -> f64 {
|
|
530
531
|
let failures = consecutive_failures.saturating_sub(1).min(5);
|
|
531
532
|
let exp = i32::try_from(failures).unwrap_or(5);
|
|
532
533
|
(interval * 2f64.powi(exp)).min(BACKOFF_MAX_SEC)
|
|
@@ -538,10 +539,6 @@ impl ProviderRegistry for RealProviderRegistry {
|
|
|
538
539
|
fn adapter_for(&self, provider: Provider) -> Box<dyn ProviderAdapter> {
|
|
539
540
|
crate::provider::get_adapter(provider)
|
|
540
541
|
}
|
|
541
|
-
|
|
542
|
-
fn error_lists(&self, _provider: Provider) -> ErrorLists {
|
|
543
|
-
ErrorLists::default()
|
|
544
|
-
}
|
|
545
542
|
}
|
|
546
543
|
|
|
547
544
|
fn sleep_seconds(seconds: f64) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! Windows ConPTY shim lifecycle manager.
|
|
2
3
|
//!
|
|
3
4
|
//! 0.5.x Windows portability Batch 6 Option A. The design's
|
|
@@ -160,7 +161,7 @@ pub enum ShimError {
|
|
|
160
161
|
/// installations.
|
|
161
162
|
/// 2. Env override `TEAM_AGENT_WINDOWS_SHIM_PATH` — tests + CI
|
|
162
163
|
/// harness (Batch 6 SSH real-machine harness sets this).
|
|
163
|
-
|
|
164
|
+
fn locate_shim_binary() -> Result<PathBuf, ShimError> {
|
|
164
165
|
if let Ok(explicit) = std::env::var("TEAM_AGENT_WINDOWS_SHIM_PATH") {
|
|
165
166
|
let p = PathBuf::from(&explicit);
|
|
166
167
|
if p.exists() {
|
|
@@ -218,7 +219,7 @@ fn fresh_pipe_token() -> String {
|
|
|
218
219
|
/// downstream `transport_factory::conpty_pipe_ready(...)` opens on
|
|
219
220
|
/// the next factory resolve. The `pipe_token` is NOT persisted (CR
|
|
220
221
|
/// C-1); it stays in `ShimHandle` memory only.
|
|
221
|
-
|
|
222
|
+
fn spawn_shim_and_handshake(
|
|
222
223
|
workspace: &Path,
|
|
223
224
|
team_key: &str,
|
|
224
225
|
workspace_hash: &str,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! step 12 · coordinator — daemon lifecycle / single-tick orchestration SKELETON (ROUND-0).
|
|
2
3
|
//!
|
|
3
4
|
//! Card: `docs/phase0/subsystems/12-coordinator.md`.
|
|
@@ -10,8 +11,7 @@
|
|
|
10
11
|
//! - `coordinator/metadata.py` (COORDINATOR_PROTOCOL_VERSION=2, pid_is_running, read/write/ok meta)
|
|
11
12
|
//! - `coordinator/paths.py` (coordinator.pid / coordinator.json / coordinator.log paths)
|
|
12
13
|
//! - `watch/__init__.py` (run_watch / collect_watch_lines / render_event_line / WatchCursor)
|
|
13
|
-
//! - `abnormal_track.py` (Gap 32 §4 provider-neutral
|
|
14
|
-
//! process_abnormal_records / detect_whole_team_gone)
|
|
14
|
+
//! - `abnormal_track.py` (Gap 32 §4 provider-neutral whole-team-gone detection)
|
|
15
15
|
//!
|
|
16
16
|
//! 职责(card §职责):per-workspace daemon 生命周期 + 单次 tick 编排。tick 按固定顺序把
|
|
17
17
|
//! step 8-11 的原子操作串成一个只读 + 投递既定 obligation 的回路 —— **绝不**在无 pending
|
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
//!
|
|
2
|
-
|
|
3
|
-
use std::hash::{Hash, Hasher};
|
|
4
|
-
|
|
5
|
-
use serde_json::Value;
|
|
6
|
-
|
|
7
|
-
use crate::model::enums::Provider;
|
|
8
|
-
use crate::provider::{ProcessLiveness, Signature, TurnId, TurnState};
|
|
1
|
+
//!
|
|
2
|
+
//! 孤儿自终止判定(Gap 37b)+ provider-neutral 整队消失检测。
|
|
9
3
|
|
|
10
4
|
use super::types::{
|
|
11
|
-
|
|
12
|
-
AbnormalProcessOutput, MarkerStore, ProviderRegistry, TeamPresenceSnapshot, WholeTeamGoneClass,
|
|
13
|
-
WholeTeamGoneReport, WorkspacePath,
|
|
5
|
+
MarkerStore, TeamPresenceSnapshot, WholeTeamGoneClass, WholeTeamGoneReport, WorkspacePath,
|
|
14
6
|
};
|
|
15
7
|
|
|
8
|
+
///
|
|
16
9
|
/// 孤儿自终止判定(`__main__.py:51-59`,Gap 37b)。仅当
|
|
17
10
|
/// `current_ppid != initial_ppid ∧ current_ppid == 1 ∧ !workspace.exists()` 三者**同时**成立 → true。
|
|
18
11
|
/// 少一个条件都不能误杀正常 daemon(card §91)。
|
|
@@ -28,104 +21,7 @@ pub fn should_orphan_self_terminate(
|
|
|
28
21
|
// abnormal_track 公共面(abnormal_track.py)—— Gap 32 §4 provider-neutral
|
|
29
22
|
// ===========================================================================
|
|
30
23
|
|
|
31
|
-
/// #236 dedicated `worker.abnormal_exit` surface.
|
|
32
24
|
///
|
|
33
|
-
/// This is intentionally separate from `process_abnormal_records`: the generic
|
|
34
|
-
/// abnormal path is transcript-only, while `worker.abnormal_exit` requires a fresh
|
|
35
|
-
/// latest explicit provider error before leader notification.
|
|
36
|
-
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
|
37
|
-
#[serde(tag = "event")]
|
|
38
|
-
pub enum WorkerAbnormalExitSurface {
|
|
39
|
-
#[serde(rename = "worker.abnormal_exit")]
|
|
40
|
-
WorkerAbnormalExit {
|
|
41
|
-
agent_id: String,
|
|
42
|
-
provider: Provider,
|
|
43
|
-
path: String,
|
|
44
|
-
provider_process_dead: bool,
|
|
45
|
-
latest_explicit_error: bool,
|
|
46
|
-
signature: Signature,
|
|
47
|
-
turn_id: Option<TurnId>,
|
|
48
|
-
process_liveness: ProcessLiveness,
|
|
49
|
-
},
|
|
50
|
-
#[serde(rename = "abnormal_exit.single_signal_suppressed")]
|
|
51
|
-
SingleSignalSuppressed {
|
|
52
|
-
agent_id: String,
|
|
53
|
-
provider: Provider,
|
|
54
|
-
path: String,
|
|
55
|
-
provider_process_dead: bool,
|
|
56
|
-
latest_explicit_error: bool,
|
|
57
|
-
reason: String,
|
|
58
|
-
},
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/// `process_abnormal_records`(`abnormal_track.py:14`)。把原始 provider session records 经
|
|
62
|
-
/// provider reader 翻译成结构化 fault facts(本 module **不命名 provider、不读屏**),catch-bias
|
|
63
|
-
/// (C9)+ `(signature, turn_id|fingerprint)` 去重(C8)。`registry` 携带 provider + 黑白名单。
|
|
64
|
-
pub fn process_abnormal_records(
|
|
65
|
-
records: &[Value],
|
|
66
|
-
registry: &dyn ProviderRegistry,
|
|
67
|
-
provider: Provider,
|
|
68
|
-
notification_state: &AbnormalNotificationState,
|
|
69
|
-
) -> Result<AbnormalProcessOutput, AbnormalError> {
|
|
70
|
-
let lists = registry.error_lists(provider);
|
|
71
|
-
let mut state = notification_state.clone();
|
|
72
|
-
let mut notifications = Vec::new();
|
|
73
|
-
for record in records {
|
|
74
|
-
let raw = record
|
|
75
|
-
.get("raw")
|
|
76
|
-
.and_then(Value::as_str)
|
|
77
|
-
.unwrap_or_else(|| record.as_str().unwrap_or(""))
|
|
78
|
-
.to_string();
|
|
79
|
-
let signature = record
|
|
80
|
-
.get("signature")
|
|
81
|
-
.and_then(Value::as_str)
|
|
82
|
-
.unwrap_or("unknown")
|
|
83
|
-
.to_string();
|
|
84
|
-
let signature_lower = signature.to_lowercase();
|
|
85
|
-
let turn_id = record
|
|
86
|
-
.get("turn_id")
|
|
87
|
-
.and_then(Value::as_str)
|
|
88
|
-
.map(TurnId::new);
|
|
89
|
-
let bucket = match &turn_id {
|
|
90
|
-
Some(id) => id.as_str().to_string(),
|
|
91
|
-
None => stable_fingerprint(record),
|
|
92
|
-
};
|
|
93
|
-
let key = format!("{signature}\0{bucket}");
|
|
94
|
-
if state.seen.contains(&key) {
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
state.seen.insert(key);
|
|
98
|
-
if lists.whitelist.iter().any(|needle| raw.contains(needle)) {
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
let decision =
|
|
102
|
-
if lists.blacklist.iter().any(|needle| {
|
|
103
|
-
raw.contains(needle) || signature_lower.contains(&needle.to_lowercase())
|
|
104
|
-
}) {
|
|
105
|
-
AbnormalDecision::NotifyBlacklist
|
|
106
|
-
} else {
|
|
107
|
-
AbnormalDecision::NotifyDefault
|
|
108
|
-
};
|
|
109
|
-
let kind = record.get("kind").and_then(Value::as_str);
|
|
110
|
-
notifications.push(AbnormalNotification {
|
|
111
|
-
signature,
|
|
112
|
-
turn_id,
|
|
113
|
-
state: if kind == Some("approval") {
|
|
114
|
-
TurnState::BlockedOnHuman
|
|
115
|
-
} else {
|
|
116
|
-
TurnState::Abnormal
|
|
117
|
-
},
|
|
118
|
-
decision,
|
|
119
|
-
provider: Some(provider),
|
|
120
|
-
raw: record.clone(),
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
Ok(AbnormalProcessOutput {
|
|
124
|
-
notifications,
|
|
125
|
-
notification_state: state,
|
|
126
|
-
})
|
|
127
|
-
}
|
|
128
|
-
|
|
129
25
|
/// `detect_whole_team_gone`(`abnormal_track.py:91`,C10/C13)。coordinator-independent 整队消失检测:
|
|
130
26
|
/// 全死(coordinator + leader + 所有 worker + 所有 session)且非 clean_shutdown/restart →
|
|
131
27
|
/// 写 durable marker + 延迟到下条 leader 命令再 escalate。clean/restart 静默。
|
|
@@ -166,14 +62,6 @@ pub fn detect_whole_team_gone(
|
|
|
166
62
|
)
|
|
167
63
|
}
|
|
168
64
|
|
|
169
|
-
fn stable_fingerprint(value: &Value) -> String {
|
|
170
|
-
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
|
171
|
-
serde_json::to_string(value)
|
|
172
|
-
.unwrap_or_else(|_| value.to_string())
|
|
173
|
-
.hash(&mut hasher);
|
|
174
|
-
format!("{:016x}", hasher.finish())
|
|
175
|
-
}
|
|
176
|
-
|
|
177
65
|
fn whole_team_report(
|
|
178
66
|
whole_team_gone: bool,
|
|
179
67
|
classification: WholeTeamGoneClass,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! unit-11 (Stage 4) — coordinator tick `abnormal` step group.
|
|
2
3
|
//!
|
|
3
4
|
//! Abnormal-exit detection + classification step extracted from
|
|
@@ -15,6 +16,7 @@ use super::super::health::pid_is_running;
|
|
|
15
16
|
use super::super::tick::TickError;
|
|
16
17
|
use super::super::types::Pid;
|
|
17
18
|
|
|
19
|
+
///
|
|
18
20
|
/// #236 `worker.abnormal_exit` watcher.
|
|
19
21
|
///
|
|
20
22
|
/// Notify only when the bounded transcript/rollout tail contains a latest explicit
|
|
@@ -967,6 +969,7 @@ fn abnormal_last_error_observation_cohort(state: &Value, agent_id: &str) -> Opti
|
|
|
967
969
|
/// P1: Python `_TAIL_BYTES` parity (idle_takeover_wiring.py:13) — RS must not read less.
|
|
968
970
|
const ABNORMAL_TAIL_BYTES: u64 = 131_072;
|
|
969
971
|
|
|
972
|
+
///
|
|
970
973
|
/// P1: bounded tail read; a partial first line is harmless (the consumer only parses
|
|
971
974
|
/// the latest complete JSONL record) and lossy UTF-8 keeps a mid-codepoint seek safe.
|
|
972
975
|
pub(crate) fn read_tail_text(path: &Path, max_bytes: u64) -> std::io::Result<String> {
|
|
@@ -1347,6 +1350,7 @@ impl ApiErrorRecoveryClass {
|
|
|
1347
1350
|
}
|
|
1348
1351
|
}
|
|
1349
1352
|
|
|
1353
|
+
///
|
|
1350
1354
|
/// 0.5.36 §7.1: rules keyed on status/error text.
|
|
1351
1355
|
pub(crate) fn classify_api_error_recovery(
|
|
1352
1356
|
signature: &str,
|
|
@@ -1871,6 +1875,7 @@ fn process_api_error_recovery_intent(
|
|
|
1871
1875
|
// path (which owns its own save).
|
|
1872
1876
|
// ─────────────────────────────────────────────────────────────────────────
|
|
1873
1877
|
|
|
1878
|
+
///
|
|
1874
1879
|
/// 0.5.36 §7.3: process all due recovery intents. Called from tick.rs
|
|
1875
1880
|
/// AFTER atomic_save has flushed the detector-written intent. Reloads a
|
|
1876
1881
|
/// fresh state each call so the caller's stale in-memory state cannot
|
|
@@ -2168,7 +2173,7 @@ fn write_recovery_intent_result(workspace: &Path, agent_id: &str, update: Recove
|
|
|
2168
2173
|
mod tests {
|
|
2169
2174
|
use super::*;
|
|
2170
2175
|
use crate::coordinator::tick::Coordinator;
|
|
2171
|
-
use crate::coordinator::types::{
|
|
2176
|
+
use crate::coordinator::types::{ProviderRegistry, WorkspacePath};
|
|
2172
2177
|
use std::io::Write as _;
|
|
2173
2178
|
|
|
2174
2179
|
struct NormalRegistry;
|
|
@@ -2180,10 +2185,6 @@ mod tests {
|
|
|
2180
2185
|
) -> Box<dyn crate::provider::ProviderAdapter> {
|
|
2181
2186
|
crate::provider::get_adapter(provider)
|
|
2182
2187
|
}
|
|
2183
|
-
|
|
2184
|
-
fn error_lists(&self, _provider: crate::provider::Provider) -> ErrorLists {
|
|
2185
|
-
ErrorLists::default()
|
|
2186
|
-
}
|
|
2187
2188
|
}
|
|
2188
2189
|
#[test]
|
|
2189
2190
|
fn abnormal_stale_error_baselines_then_fresh_alive_error_notifies() {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//!
|
|
1
2
|
//! unit-11 (Stage 4) — coordinator tick steps namespace.
|
|
2
3
|
//!
|
|
3
4
|
//! The 3083 LOC `coordinator/tick.rs` orchestrator runs an ordered
|
|
@@ -47,6 +48,7 @@ impl TickStepGroup {
|
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
///
|
|
50
52
|
/// Canonical ordering as a const slice — exhaustive over the enum.
|
|
51
53
|
pub fn ordered() -> &'static [TickStepGroup] {
|
|
52
54
|
&[
|