@team-agent/installer 0.5.59 → 0.5.61
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 +44 -1
- package/crates/team-agent/src/cli/diagnose.rs +183 -0
- package/crates/team-agent/src/cli/emit.rs +63 -14
- package/crates/team-agent/src/cli/leader.rs +8 -1
- package/crates/team-agent/src/cli/mod.rs +263 -5
- package/crates/team-agent/src/cli/named_address.rs +18 -1
- package/crates/team-agent/src/cli/send/presentation.rs +2 -0
- package/crates/team-agent/src/cli/spec.rs +4 -1
- 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/types.rs +33 -0
- package/crates/team-agent/src/communication_mode/mod.rs +53 -0
- package/crates/team-agent/src/compiler/tests.rs +5 -5
- package/crates/team-agent/src/compiler.rs +53 -1
- package/crates/team-agent/src/coordinator/tick.rs +21 -8
- package/crates/team-agent/src/db/message_store.rs +45 -1
- package/crates/team-agent/src/fake_worker.rs +21 -1
- package/crates/team-agent/src/leader/start.rs +732 -94
- package/crates/team-agent/src/leader/tests/identity.rs +64 -57
- package/crates/team-agent/src/leader/tests/identity_session_names.rs +42 -0
- package/crates/team-agent/src/lib.rs +4 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +58 -0
- package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +57 -51
- package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +148 -8
- package/crates/team-agent/src/lifecycle/launch/fork_state.rs +5 -0
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +1 -1
- package/crates/team-agent/src/lifecycle/launch.rs +1 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +1 -1
- package/crates/team-agent/src/lifecycle/restart/common.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +35 -1
- package/crates/team-agent/src/lifecycle/types.rs +1 -0
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +29 -11
- package/crates/team-agent/src/mcp_server/normalize.rs +1 -0
- 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 +100 -66
- package/crates/team-agent/src/mcp_server/types.rs +5 -0
- package/crates/team-agent/src/mcp_server/wire.rs +27 -21
- package/crates/team-agent/src/messaging/delivery.rs +105 -38
- package/crates/team-agent/src/messaging/leader_channel.rs +33 -10
- package/crates/team-agent/src/messaging/leader_receiver.rs +40 -23
- package/crates/team-agent/src/messaging/presentation.rs +109 -0
- package/crates/team-agent/src/messaging/results.rs +165 -17
- package/crates/team-agent/src/messaging/send.rs +94 -81
- 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/runtime.rs +13 -6
- package/crates/team-agent/src/messaging/types.rs +5 -0
- package/crates/team-agent/src/messaging/watchers.rs +5 -0
- package/crates/team-agent/src/model/mod.rs +1 -0
- package/crates/team-agent/src/model/pane_authority_refusal.rs +358 -0
- package/crates/team-agent/src/model/spec.rs +16 -0
- package/crates/team-agent/src/provider/adapter.rs +57 -0
- package/crates/team-agent/src/provider/adapters/claude_fork.rs +10 -2
- package/crates/team-agent/src/provider/session/capture.rs +69 -34
- package/crates/team-agent/src/provider/session/context_fork/codex.rs +386 -9
- package/crates/team-agent/src/provider/session/context_fork/outcome.rs +3 -14
- package/crates/team-agent/src/provider/session/context_fork.rs +7 -2
- package/crates/team-agent/src/provider/session/mod.rs +3 -2
- package/crates/team-agent/src/provider/session_scan/claude.rs +92 -3
- package/crates/team-agent/src/provider/session_scan/codex.rs +28 -0
- package/crates/team-agent/src/provider/session_scan/common.rs +34 -8
- package/crates/team-agent/src/provider/session_scan.rs +8 -0
- package/crates/team-agent/src/topology.rs +3 -0
- package/package.json +4 -4
- package/skills/team-agent/command-coverage.json +379 -0
|
@@ -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() {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
use std::fs;
|
|
27
27
|
use std::path::Path;
|
|
28
28
|
|
|
29
|
+
use crate::communication_mode::CommunicationMode;
|
|
29
30
|
use crate::model::enums::{Provider, ProviderEffort};
|
|
30
31
|
use crate::model::yaml::Value;
|
|
31
32
|
use crate::model::{paths, spec, yaml, ModelError};
|
|
@@ -133,6 +134,8 @@ pub fn compile_team(team_dir: &Path) -> Result<Value, ModelError> {
|
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
let (team_meta, team_body) = read_front_matter(&team_md)?;
|
|
137
|
+
let team_communication_mode =
|
|
138
|
+
communication_mode_field(&team_meta, &team_md)?.unwrap_or_default();
|
|
136
139
|
let mut role_paths = Vec::new();
|
|
137
140
|
if agents_dir.is_dir() {
|
|
138
141
|
for entry in fs::read_dir(&agents_dir)
|
|
@@ -170,7 +173,8 @@ pub fn compile_team(team_dir: &Path) -> Result<Value, ModelError> {
|
|
|
170
173
|
let mut agents = Vec::new();
|
|
171
174
|
let mut agent_ids = Vec::new();
|
|
172
175
|
for path in role_paths {
|
|
173
|
-
let compiled =
|
|
176
|
+
let compiled =
|
|
177
|
+
compile_role_agent_with_mode(&path, &team_meta, &workspace_s, team_communication_mode)?;
|
|
174
178
|
agent_ids.push(compiled.id);
|
|
175
179
|
agents.push(compiled.agent);
|
|
176
180
|
}
|
|
@@ -371,8 +375,21 @@ pub fn compile_role_agent(
|
|
|
371
375
|
role_path: &Path,
|
|
372
376
|
team_meta: &Value,
|
|
373
377
|
workspace_s: &str,
|
|
378
|
+
) -> Result<CompiledRole, ModelError> {
|
|
379
|
+
let team_communication_mode =
|
|
380
|
+
communication_mode_field(team_meta, role_path)?.unwrap_or_default();
|
|
381
|
+
compile_role_agent_with_mode(role_path, team_meta, workspace_s, team_communication_mode)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
fn compile_role_agent_with_mode(
|
|
385
|
+
role_path: &Path,
|
|
386
|
+
team_meta: &Value,
|
|
387
|
+
workspace_s: &str,
|
|
388
|
+
team_communication_mode: CommunicationMode,
|
|
374
389
|
) -> Result<CompiledRole, ModelError> {
|
|
375
390
|
let (meta, body) = read_front_matter(role_path)?;
|
|
391
|
+
let communication_mode =
|
|
392
|
+
communication_mode_field(&meta, role_path)?.unwrap_or(team_communication_mode);
|
|
376
393
|
let id = required_string(&meta, role_path, "name")?;
|
|
377
394
|
let role = required_string(&meta, role_path, "role")?;
|
|
378
395
|
let provider = required_string(&meta, role_path, "provider")?;
|
|
@@ -404,6 +421,10 @@ pub fn compile_role_agent(
|
|
|
404
421
|
),
|
|
405
422
|
("tools", list_str(tools)),
|
|
406
423
|
("permission_mode", Value::Str("restricted".to_string())),
|
|
424
|
+
(
|
|
425
|
+
"communication_mode",
|
|
426
|
+
Value::Str(communication_mode.as_str().to_string()),
|
|
427
|
+
),
|
|
407
428
|
("preferred_for", list_str(vec![id.clone(), role.clone()])),
|
|
408
429
|
("avoid_for", Value::List(Vec::new())),
|
|
409
430
|
(
|
|
@@ -469,6 +490,37 @@ pub fn compile_role_agent(
|
|
|
469
490
|
})
|
|
470
491
|
}
|
|
471
492
|
|
|
493
|
+
fn communication_mode_field(
|
|
494
|
+
meta: &Value,
|
|
495
|
+
path: &Path,
|
|
496
|
+
) -> Result<Option<CommunicationMode>, ModelError> {
|
|
497
|
+
let Some(raw) = meta.get("communication_mode") else {
|
|
498
|
+
return Ok(None);
|
|
499
|
+
};
|
|
500
|
+
let Some(value) = raw.as_str() else {
|
|
501
|
+
return Err(ModelError::Validation(format!(
|
|
502
|
+
"{}: unknown communication_mode (allowed: {})",
|
|
503
|
+
path.display(),
|
|
504
|
+
CommunicationMode::ALL
|
|
505
|
+
.iter()
|
|
506
|
+
.map(|mode| mode.as_str())
|
|
507
|
+
.collect::<Vec<_>>()
|
|
508
|
+
.join("|")
|
|
509
|
+
)));
|
|
510
|
+
};
|
|
511
|
+
CommunicationMode::parse(value).map(Some).ok_or_else(|| {
|
|
512
|
+
ModelError::Validation(format!(
|
|
513
|
+
"{}: unknown communication_mode '{value}' (allowed: {})",
|
|
514
|
+
path.display(),
|
|
515
|
+
CommunicationMode::ALL
|
|
516
|
+
.iter()
|
|
517
|
+
.map(|mode| mode.as_str())
|
|
518
|
+
.collect::<Vec<_>>()
|
|
519
|
+
.join("|")
|
|
520
|
+
))
|
|
521
|
+
})
|
|
522
|
+
}
|
|
523
|
+
|
|
472
524
|
fn map(items: Vec<(&str, Value)>) -> Value {
|
|
473
525
|
Value::Map(items.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
|
|
474
526
|
}
|
|
@@ -269,12 +269,17 @@ impl Coordinator {
|
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
self.record_step("capture_missing");
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
272
|
+
let pending_context_fork_audits =
|
|
273
|
+
match self.capture_missing_sessions(&mut state, &event_log) {
|
|
274
|
+
Ok(audits) => audits,
|
|
275
|
+
Err(error) => {
|
|
276
|
+
let _ = event_log.write(
|
|
277
|
+
"coordinator.tick.capture_missing_failed",
|
|
278
|
+
serde_json::json!({"error": error.to_string()}),
|
|
279
|
+
);
|
|
280
|
+
Vec::new()
|
|
281
|
+
}
|
|
282
|
+
};
|
|
278
283
|
|
|
279
284
|
// Slice 1 energy gate: one pane snapshot per tick feeds probe eligibility,
|
|
280
285
|
// health sync, and abnormal-exit detection. Missing panes are filtered
|
|
@@ -454,6 +459,14 @@ impl Coordinator {
|
|
|
454
459
|
collections,
|
|
455
460
|
));
|
|
456
461
|
}
|
|
462
|
+
for context_fork in &pending_context_fork_audits {
|
|
463
|
+
context_fork.write_audit(&event_log).map_err(|error| {
|
|
464
|
+
eprintln!(
|
|
465
|
+
"[coordinator] context_fork audit publish failed after state commit: {error}"
|
|
466
|
+
);
|
|
467
|
+
TickError::EventLog(error)
|
|
468
|
+
})?;
|
|
469
|
+
}
|
|
457
470
|
|
|
458
471
|
// 0.5.36 (`.team/artifacts/supermarket-api-error-recovery-locate.md` §7.3):
|
|
459
472
|
// post-save recovery step. Reloads fresh state, consumes due
|
|
@@ -487,7 +500,7 @@ impl Coordinator {
|
|
|
487
500
|
&self,
|
|
488
501
|
state: &mut Value,
|
|
489
502
|
event_log: &EventLog,
|
|
490
|
-
) -> Result<
|
|
503
|
+
) -> Result<Vec<crate::lifecycle::launch::ContextForkFinalized>, TickError> {
|
|
491
504
|
let report = crate::session_capture::capture_missing_provider_sessions_once(
|
|
492
505
|
state,
|
|
493
506
|
&mut |provider| self.provider_registry.adapter_for(provider),
|
|
@@ -651,7 +664,7 @@ impl Coordinator {
|
|
|
651
664
|
}),
|
|
652
665
|
)?;
|
|
653
666
|
}
|
|
654
|
-
Ok(
|
|
667
|
+
Ok(report.context_forks)
|
|
655
668
|
}
|
|
656
669
|
|
|
657
670
|
fn sync_agent_health(
|
|
@@ -97,6 +97,7 @@ pub enum MessageRowStatus {
|
|
|
97
97
|
QueuedPaneMissing,
|
|
98
98
|
TargetResolved,
|
|
99
99
|
SubmittedAwaitingReceipt,
|
|
100
|
+
InjectedAwaitingReceipt,
|
|
100
101
|
SubmittedUnverified,
|
|
101
102
|
Delivered,
|
|
102
103
|
Acknowledged,
|
|
@@ -115,6 +116,7 @@ impl MessageRowStatus {
|
|
|
115
116
|
Self::QueuedPaneMissing,
|
|
116
117
|
Self::TargetResolved,
|
|
117
118
|
Self::SubmittedAwaitingReceipt,
|
|
119
|
+
Self::InjectedAwaitingReceipt,
|
|
118
120
|
Self::SubmittedUnverified,
|
|
119
121
|
Self::Delivered,
|
|
120
122
|
Self::Acknowledged,
|
|
@@ -133,6 +135,7 @@ impl MessageRowStatus {
|
|
|
133
135
|
Self::QueuedPaneMissing => "queued_pane_missing",
|
|
134
136
|
Self::TargetResolved => "target_resolved",
|
|
135
137
|
Self::SubmittedAwaitingReceipt => "submitted_pending_acceptance",
|
|
138
|
+
Self::InjectedAwaitingReceipt => "injected_awaiting_receipt",
|
|
136
139
|
Self::SubmittedUnverified => "submitted_unverified",
|
|
137
140
|
Self::Delivered => "delivered",
|
|
138
141
|
Self::Acknowledged => "acknowledged",
|
|
@@ -394,7 +397,10 @@ impl MessageStore {
|
|
|
394
397
|
acknowledged_at = case when ?2 = 'acknowledged' then ?3 else acknowledged_at end,
|
|
395
398
|
error = case when ?2 = 'delivered' then null else coalesce(?4, error) end
|
|
396
399
|
where message_id = ?1
|
|
397
|
-
and status not in (
|
|
400
|
+
and status not in (
|
|
401
|
+
'acknowledged', 'consumed', 'submitted_pending_acceptance',
|
|
402
|
+
'injected_awaiting_receipt'
|
|
403
|
+
)
|
|
398
404
|
and (status != 'delivered' or ?2 in ('delivered', 'acknowledged'))
|
|
399
405
|
and (?2 != 'acknowledged' or status = 'delivered')",
|
|
400
406
|
params![message_id, status, now, error],
|
|
@@ -468,6 +474,44 @@ impl MessageStore {
|
|
|
468
474
|
Ok(())
|
|
469
475
|
}
|
|
470
476
|
|
|
477
|
+
/// Persist a verified leader transport submission when no provider receipt
|
|
478
|
+
/// source is available. This state is claim/requeue-ineligible but does not
|
|
479
|
+
/// clear the delivery obligation; `consumed_at` remains unset until a
|
|
480
|
+
/// provider-side receipt reaches `mark_delivered_with_receipt`.
|
|
481
|
+
pub fn mark_injected_awaiting_receipt(
|
|
482
|
+
&self,
|
|
483
|
+
message_id: &str,
|
|
484
|
+
) -> Result<(), MessageStoreError> {
|
|
485
|
+
let conn = crate::db::schema::open_db(&self.path)?;
|
|
486
|
+
let changed = conn.execute(
|
|
487
|
+
"update messages
|
|
488
|
+
set status = ?2,
|
|
489
|
+
updated_at = ?3,
|
|
490
|
+
error = 'leader_receipt_source_unavailable'
|
|
491
|
+
where message_id = ?1
|
|
492
|
+
and status in (?4, ?5, ?6)
|
|
493
|
+
and exists (
|
|
494
|
+
select 1 from delivery_tokens
|
|
495
|
+
where delivery_tokens.message_id = messages.message_id
|
|
496
|
+
and delivery_tokens.injected_at is not null
|
|
497
|
+
)",
|
|
498
|
+
params![
|
|
499
|
+
message_id,
|
|
500
|
+
MessageRowStatus::InjectedAwaitingReceipt.as_str(),
|
|
501
|
+
now_ts(),
|
|
502
|
+
MessageRowStatus::TargetResolved.as_str(),
|
|
503
|
+
MessageRowStatus::SubmittedAwaitingReceipt.as_str(),
|
|
504
|
+
MessageRowStatus::InjectedAwaitingReceipt.as_str(),
|
|
505
|
+
],
|
|
506
|
+
)?;
|
|
507
|
+
if changed != 1 {
|
|
508
|
+
return Err(MessageStoreError::DeliveryReceiptMissing(
|
|
509
|
+
message_id.to_string(),
|
|
510
|
+
));
|
|
511
|
+
}
|
|
512
|
+
Ok(())
|
|
513
|
+
}
|
|
514
|
+
|
|
471
515
|
/// Atomically persist the provider-side receipt and advance the message to
|
|
472
516
|
/// delivered. A transport-only caller cannot use this without first
|
|
473
517
|
/// recording the submission row above.
|
|
@@ -153,7 +153,7 @@ fn fake_envelope(
|
|
|
153
153
|
) -> serde_json::Value {
|
|
154
154
|
serde_json::json!({
|
|
155
155
|
"schema_version": "result_envelope_v1",
|
|
156
|
-
"task_id": task_id.unwrap_or(
|
|
156
|
+
"task_id": task_id.unwrap_or(message_id),
|
|
157
157
|
"agent_id": agent_id,
|
|
158
158
|
"status": "success",
|
|
159
159
|
"summary": format!("Fake worker handled message {message_id}"),
|
|
@@ -280,4 +280,24 @@ mod tests {
|
|
|
280
280
|
"rendered form prints WORKING per line; got {printed}"
|
|
281
281
|
);
|
|
282
282
|
}
|
|
283
|
+
|
|
284
|
+
#[test]
|
|
285
|
+
fn fake_worker_direct_message_uses_message_scope_instead_of_manual() {
|
|
286
|
+
let ws = fake_ws();
|
|
287
|
+
let input = "Team Agent message from leader:\nplease do X\n[team-agent-token:m1]\n";
|
|
288
|
+
let mut out: Vec<u8> = Vec::new();
|
|
289
|
+
run(&ws, "w1", Cursor::new(input.as_bytes()), &mut out).expect("fake worker run");
|
|
290
|
+
|
|
291
|
+
let (task_id, agent_id, status, envelope) = stored_result(&ws);
|
|
292
|
+
assert_eq!(
|
|
293
|
+
(task_id.as_str(), agent_id.as_str(), status.as_str()),
|
|
294
|
+
("m1", "w1", "success"),
|
|
295
|
+
"a direct-message result must use its message id for message-scope collection"
|
|
296
|
+
);
|
|
297
|
+
assert_ne!(
|
|
298
|
+
envelope["task_id"],
|
|
299
|
+
serde_json::json!("manual"),
|
|
300
|
+
"the fake worker must not emit the production-impossible manual fallback"
|
|
301
|
+
);
|
|
302
|
+
}
|
|
283
303
|
}
|