@team-agent/installer 0.5.81 → 0.5.82

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 CHANGED
@@ -581,7 +581,7 @@ dependencies = [
581
581
 
582
582
  [[package]]
583
583
  name = "team-agent"
584
- version = "0.5.81"
584
+ version = "0.5.82"
585
585
  dependencies = [
586
586
  "anyhow",
587
587
  "chrono",
package/Cargo.toml CHANGED
@@ -9,7 +9,7 @@ members = ["crates/team-agent", "crates/win-conpty-phase0", "crates/conpty-trans
9
9
 
10
10
  [workspace.package]
11
11
  edition = "2021"
12
- version = "0.5.81"
12
+ version = "0.5.82"
13
13
  license = "AGPL-3.0"
14
14
  rust-version = "1.95"
15
15
 
@@ -12,9 +12,9 @@ const LEADER_CENTRIC_RUNTIME_CONTRACT: &str = r#"# Team Agent communication cont
12
12
 
13
13
  - Progress, blockers, questions: {send_message}(to='leader', content='...')
14
14
 
15
- When you receive a message from the leader or a teammate, you MUST respond
16
- through MCP tools. Writing a reply in your terminal does nothing — the sender
17
- will never see it."#;
15
+ Respond through Team Agent MCP tools only to actionable requests or questions; writing in your terminal does not deliver it.
16
+
17
+ "#;
18
18
 
19
19
  const ORCHESTRATED_RUNTIME_CONTRACT: &str = r#"# Team Agent communication contract: orchestrated
20
20
 
@@ -1089,7 +1089,6 @@ fn materialize_pi_plan_with_session(
1089
1089
  })?;
1090
1090
  let (argv, expected_session_id) = if let Some((_session_id, exact_path)) = resume {
1091
1091
  let argv = build_pi_command_argv(PiCommandRequest {
1092
- executable: &chain.launch_executable,
1093
1092
  extension: &wrapper,
1094
1093
  model: model.as_deref(),
1095
1094
  effort: request.effort,
@@ -1103,7 +1102,6 @@ fn materialize_pi_plan_with_session(
1103
1102
  } else {
1104
1103
  let session_id = new_pi_session_id();
1105
1104
  let argv = build_pi_command_argv(PiCommandRequest {
1106
- executable: &chain.launch_executable,
1107
1105
  extension: &wrapper,
1108
1106
  model: model.as_deref(),
1109
1107
  effort: request.effort,
@@ -112,7 +112,13 @@ fn t06_selected_templates_project_the_two_signed_communication_boundaries() {
112
112
  };
113
113
 
114
114
  let leader = prompt(CommunicationMode::LeaderCentric);
115
- for marker in ["Progress", "blocker", "question"] {
115
+ for marker in [
116
+ "Progress",
117
+ "blocker",
118
+ "question",
119
+ "actionable requests or questions",
120
+ "Do not reply to pure ACKs, greetings, or unchanged status notices",
121
+ ] {
116
122
  assert!(
117
123
  leader.contains(marker),
118
124
  "T06/leader_centric: official template must retain {marker:?} guidance; prompt={leader:?}"
@@ -120,7 +126,11 @@ fn t06_selected_templates_project_the_two_signed_communication_boundaries() {
120
126
  }
121
127
 
122
128
  let orchestrated = prompt(CommunicationMode::Orchestrated);
123
- for marker in ["declared channel", "task-related", "ACK"] {
129
+ for marker in [
130
+ "declared channel",
131
+ "Respond to task-related messages through Team Agent MCP tools.",
132
+ "A pure ACK, unrelated status, or non-task message does not require a response.",
133
+ ] {
124
134
  assert!(
125
135
  orchestrated.contains(marker),
126
136
  "T06/orchestrated: official template must state the on-demand channel/response boundary via {marker:?}; prompt={orchestrated:?}"
@@ -159,7 +169,7 @@ fn t07_final_spawn_prompt_does_not_leak_leader_centric_obligations_into_orchestr
159
169
 
160
170
  for required in [
161
171
  "All communication must go through Team Agent MCP tools.",
162
- "If blocked or waiting, send_message to the leader. Do not wait silently.",
172
+ "Do not reply to pure ACKs, greetings, or unchanged status notices",
163
173
  "report_result exactly once",
164
174
  ] {
165
175
  assert!(
@@ -186,7 +196,8 @@ fn t07_final_spawn_prompt_does_not_leak_leader_centric_obligations_into_orchestr
186
196
  .expect("T07/leader_centric positive control: missing recorded default spawn");
187
197
  for required in [
188
198
  "Progress, blockers, questions:",
189
- "When you receive a message from the leader or a teammate, you MUST respond",
199
+ "actionable requests or questions",
200
+ "Do not reply to pure ACKs, greetings, or unchanged status notices",
190
201
  ] {
191
202
  assert!(
192
203
  default_prompt.contains(required),
@@ -87,7 +87,6 @@ fn argv_has_pair(argv: &[String], flag: &str, value: &str) -> bool {
87
87
 
88
88
  fn command_for_model(model: &str) -> Vec<String> {
89
89
  build_pi_command_argv(PiCommandRequest {
90
- executable: Path::new("/verified/pi"),
91
90
  extension: Path::new("/workspace/.team/runtime/pi/t1/w1/team-mcp.ts"),
92
91
  model: Some(model),
93
92
  effort: Some(ProviderEffort::Medium),
@@ -6,7 +6,6 @@ use crate::provider::adapters::pi::{build_pi_command_argv, PiCommandRequest, PiS
6
6
 
7
7
  fn request(session: PiSessionSelector<'static>) -> PiCommandRequest<'static> {
8
8
  PiCommandRequest {
9
- executable: Path::new("/verified/pi"),
10
9
  extension: Path::new("/workspace/.team/runtime/pi/team-a/worker-a/team-mcp.ts"),
11
10
  model: Some("team-agent/qwen3.8-27b"),
12
11
  effort: Some(ProviderEffort::High),
@@ -35,7 +34,6 @@ fn pi_command_omits_unset_model_and_thinking_flags() {
35
34
 
36
35
  fn leader_request() -> PiCommandRequest<'static> {
37
36
  PiCommandRequest {
38
- executable: Path::new("/verified/pi"),
39
37
  extension: Path::new("/workspace/.team/runtime/pi/current/leader/team-mcp.ts"),
40
38
  model: None,
41
39
  effort: None,
@@ -56,7 +54,7 @@ fn pi_interactive_leader_argv_preserves_native_session_discovery() {
56
54
  assert_eq!(
57
55
  argv,
58
56
  [
59
- "/verified/pi",
57
+ "pi",
60
58
  "-e",
61
59
  "/workspace/.team/runtime/pi/current/leader/team-mcp.ts",
62
60
  "--append-system-prompt",
@@ -109,7 +107,7 @@ fn pi_command_preserves_direct_pi_defaults_with_only_team_runtime_additions() {
109
107
  assert_eq!(
110
108
  fresh,
111
109
  [
112
- "/verified/pi",
110
+ "pi",
113
111
  "-e",
114
112
  "/workspace/.team/runtime/pi/team-a/worker-a/team-mcp.ts",
115
113
  "--model",
@@ -143,6 +141,7 @@ fn pi_command_preserves_direct_pi_defaults_with_only_team_runtime_additions() {
143
141
  assert!(!resume.iter().any(|arg| arg == "--session-id"));
144
142
 
145
143
  for argv in [&fresh, &resume] {
144
+ assert_eq!(argv.first().map(String::as_str), Some("pi"));
146
145
  for forbidden in [
147
146
  "rpc",
148
147
  "--mode",
@@ -53,7 +53,6 @@ fn compile_error(result: Result<CompiledRole, ModelError>) -> ModelError {
53
53
 
54
54
  fn command(tools: &[&str], effort: ProviderEffort, model: &str) -> Result<Vec<String>, String> {
55
55
  build_pi_command_argv(PiCommandRequest {
56
- executable: Path::new("/verified/pi"),
57
56
  extension: Path::new("/workspace/.team/runtime/pi/t1/pi-worker/team-mcp.ts"),
58
57
  model: Some(model),
59
58
  effort: Some(effort),
@@ -586,6 +586,7 @@ fn pi_materializer_and_worker_routes_body(hermetic: &HermeticTestEnv) {
586
586
  !native_paths.sessions.exists(),
587
587
  "NativeDefault must not create the Team Agent seat session root"
588
588
  );
589
+ assert_eq!(native.argv.first().map(String::as_str), Some("pi"));
589
590
  for forbidden in ["--session-dir", "--cwd", "--workspace", "--session"] {
590
591
  assert!(
591
592
  !native.argv.iter().any(|arg| arg == forbidden),
@@ -614,6 +615,7 @@ fn pi_materializer_and_worker_routes_body(hermetic: &HermeticTestEnv) {
614
615
  isolated.provider_projects_root.as_deref(),
615
616
  Some(isolated_paths.sessions.as_path())
616
617
  );
618
+ assert_eq!(isolated.argv.first().map(String::as_str), Some("pi"));
617
619
  assert_session_pair(&isolated.argv, &isolated_paths.sessions);
618
620
  assert!(!isolated.argv.iter().any(|arg| arg == "--cwd"));
619
621
  assert!(!isolated.argv.iter().any(|arg| arg == "--workspace"));
@@ -645,6 +647,7 @@ fn pi_materializer_and_worker_routes_body(hermetic: &HermeticTestEnv) {
645
647
  resumed.provider_projects_root.as_deref(),
646
648
  Some(isolated_paths.sessions.as_path())
647
649
  );
650
+ assert_eq!(resumed.argv.first().map(String::as_str), Some("pi"));
648
651
  assert_session_pair(&resumed.argv, &isolated_paths.sessions);
649
652
  assert!(
650
653
  resumed
@@ -757,6 +760,7 @@ fn pi_materializer_and_worker_routes_body(hermetic: &HermeticTestEnv) {
757
760
  .any(|arg| arg.as_str() == paths.wrapper.to_string_lossy().as_ref())
758
761
  })
759
762
  .expect("transport spawn record for worker seat");
763
+ assert_eq!(record.1.first().map(String::as_str), Some("pi"));
760
764
  assert_session_pair(&record.1, &paths.sessions);
761
765
  assert!(
762
766
  !record
@@ -861,6 +865,7 @@ fn pi_materializer_and_worker_routes_body(hermetic: &HermeticTestEnv) {
861
865
  .into_iter()
862
866
  .next()
863
867
  .expect("restart must reach the worker spawn construction");
868
+ assert_eq!(restart_record.1.first().map(String::as_str), Some("pi"));
864
869
  assert_session_pair(&restart_record.1, &restart_paths.sessions);
865
870
  assert!(
866
871
  restart_record
@@ -54,7 +54,6 @@ fn scan_context(cwd: &Path, root: &Path, id: &str, generation: &str) -> CaptureS
54
54
 
55
55
  fn resume_argv(path: &Path) -> Result<Vec<String>, ProviderError> {
56
56
  build_pi_command_argv(PiCommandRequest {
57
- executable: Path::new("/verified/pi"),
58
57
  extension: Path::new("/workspace/.team/runtime/pi/team-a/worker-a/team-mcp.ts"),
59
58
  model: Some("team-agent/qwen3.8-27b"),
60
59
  effort: Some(ProviderEffort::Medium),
@@ -28,20 +28,20 @@ use crate::model::permissions::{resolve_permissions, AgentPermissionInput};
28
28
 
29
29
  const RUNTIME_CONTRACT_SECTION: &str = r#"# Team Agent Teammate Runtime Contract
30
30
 
31
- You are a teammate in a Team Agent runtime. The leader cannot see your terminal
32
- output. All communication must go through Team Agent MCP tools.
31
+ You are a Team Agent teammate; leader cannot see terminal output.
32
+ All communication must go through Team Agent MCP tools.
33
33
 
34
- ## Communication (mandatory)
34
+ ## Communication:
35
35
 
36
- - Coordinate with teammate: {send_message}(to='<agent_id>', content='...')
37
- - Broadcast to all teammates: {send_message}(to='*', content='...')
38
- - Task complete: {report_result}(summary='...') — call exactly once
36
+ - Teammate: {send_message}(to='<agent_id>', content='...')
37
+ - Broadcast: {send_message}(to='*', content='...')
38
+ - Complete: {report_result}(summary='...') — call exactly once
39
39
 
40
- ## Rules
40
+ ## Rules:
41
41
 
42
- - Do not pass sender, task_id, or schema_version — the MCP runtime fills them.
43
- - If blocked or waiting, send_message to the leader. Do not wait silently.
44
- - On 500/529/rate-limit errors, wait 1-2 minutes before retrying."#;
42
+ - Do not pass sender, task_id, or schema_version — MCP fills them.
43
+ - Do not reply to pure ACKs, greetings, or unchanged status notices (such as "paused" or "waiting"); after reporting a blocker once or completing a task, remain silent until a new actionable instruction arrives.
44
+ - On 500/529/rate limits, retry only after 1-2 minutes."#;
45
45
 
46
46
  // 0.4.11 trimmed: the runtime contract section above already covers
47
47
  // send_message signatures and report_result exactly-once. The output
@@ -363,9 +363,7 @@ fn pi_communication_contract(mode: CommunicationMode) -> String {
363
363
 
364
364
  - Progress, blockers, questions: mcp({tool:"team_orchestrator_send_message", args:{to:"leader", content:"..."}})
365
365
 
366
- When you receive a message from the leader or a teammate, you MUST respond
367
- through MCP tools. Writing a reply in your terminal does nothing — the sender
368
- will never see it."#
366
+ Respond through Team Agent MCP tools only to actionable requests or questions; writing in your terminal does not deliver it."#
369
367
  .to_string(),
370
368
  CommunicationMode::Orchestrated => mode.runtime_contract("mcp"),
371
369
  }
@@ -598,4 +596,40 @@ mod tests {
598
596
  assert!(prompt.contains(&slowdown_phrase));
599
597
  assert!(prompt.contains("Runtime Developer"));
600
598
  }
599
+
600
+ #[test]
601
+ fn all_provider_mode_prompts_share_silence_contract_without_unconditional_replies() {
602
+ for provider in [Provider::Codex, Provider::Pi] {
603
+ for mode in CommunicationMode::ALL.iter().copied() {
604
+ let agent = WorkerCommandAgent {
605
+ id: Some("worker".to_string()),
606
+ provider,
607
+ role: Some("developer".to_string()),
608
+ declared_tools: Some(vec!["mcp_team".to_string()]),
609
+ system_prompt_inline: Some("worker body".to_string()),
610
+ system_prompt_file: None,
611
+ output_contract_format: Some("result_envelope_v1".to_string()),
612
+ communication_mode: mode,
613
+ dangerously_skip_permissions: false,
614
+ };
615
+ let prompt = compile_worker_system_prompt(&agent).unwrap();
616
+ assert!(prompt.contains(
617
+ "Do not reply to pure ACKs, greetings, or unchanged status notices (such as \"paused\" or \"waiting\"); after reporting a blocker once or completing a task, remain silent until a new actionable instruction arrives."
618
+ ));
619
+ assert!(!prompt.contains("Silence and resumption (mandatory)"));
620
+ assert!(!prompt.contains("When you receive a message from the leader or a teammate, you MUST respond"));
621
+ match mode {
622
+ CommunicationMode::LeaderCentric => {
623
+ assert!(prompt.contains(
624
+ "Respond through Team Agent MCP tools only to actionable requests or questions; writing in your terminal does not deliver it."
625
+ ));
626
+ }
627
+ CommunicationMode::Orchestrated => {
628
+ assert!(prompt.contains("Respond to task-related messages through Team Agent MCP tools."));
629
+ assert!(prompt.contains("A pure ACK, unrelated status, or non-task message does not require a response."));
630
+ }
631
+ }
632
+ }
633
+ }
634
+ }
601
635
  }
@@ -58,7 +58,6 @@ pub(crate) enum PiSessionSelector<'a> {
58
58
  }
59
59
 
60
60
  pub(crate) struct PiCommandRequest<'a> {
61
- pub executable: &'a Path,
62
61
  pub extension: &'a Path,
63
62
  pub model: Option<&'a str>,
64
63
  pub effort: Option<ProviderEffort>,
@@ -72,14 +71,13 @@ pub(crate) struct PiCommandRequest<'a> {
72
71
 
73
72
  /// ---
74
73
  /// purpose: 从已验证 semantic request 构造仅追加 Team Agent MCP/提示/session 的 Pi argv
75
- /// returns: exact ordered fresh/resume argv
74
+ /// returns: exact ordered fresh/resume argv,argv[0] 固定为裸 `pi`
76
75
  /// errors: 必需字段、mcp_team 或工具 category 非法时返回 ProviderError
77
76
  /// ---
78
77
  pub(crate) fn build_pi_command_argv(
79
78
  request: PiCommandRequest<'_>,
80
79
  ) -> Result<Vec<String>, ProviderError> {
81
- if request.executable.as_os_str().is_empty()
82
- || request.extension.as_os_str().is_empty()
80
+ if request.extension.as_os_str().is_empty()
83
81
  || request
84
82
  .session_dir
85
83
  .is_some_and(|session_dir| session_dir.as_os_str().is_empty())
@@ -88,7 +86,7 @@ pub(crate) fn build_pi_command_argv(
88
86
  || request.agent_id.trim().is_empty()
89
87
  {
90
88
  return Err(ProviderError::Command(
91
- "Pi command requires executable, extension, prompt, and agent id".to_string(),
89
+ "Pi command requires extension, prompt, and agent id".to_string(),
92
90
  ));
93
91
  }
94
92
 
@@ -110,8 +108,10 @@ pub(crate) fn build_pi_command_argv(
110
108
  ));
111
109
  }
112
110
 
111
+ // Executable discovery/preflight belongs to the lifecycle materializer;
112
+ // the actual command must remain PATH-resolved at spawn time.
113
113
  let mut argv = vec![
114
- request.executable.to_string_lossy().into_owned(),
114
+ "pi".to_string(),
115
115
  "-e".to_string(),
116
116
  request.extension.to_string_lossy().into_owned(),
117
117
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-agent/installer",
3
- "version": "0.5.81",
3
+ "version": "0.5.82",
4
4
  "description": "npx installer for Team Agent",
5
5
  "keywords": [
6
6
  "codex",
@@ -20,9 +20,9 @@
20
20
  "team-agent-installer": "npm/install.mjs"
21
21
  },
22
22
  "optionalDependencies": {
23
- "@team-agent/cli-darwin-arm64": "0.5.81",
24
- "@team-agent/cli-darwin-x64": "0.5.81",
25
- "@team-agent/cli-linux-x64": "0.5.81"
23
+ "@team-agent/cli-darwin-arm64": "0.5.82",
24
+ "@team-agent/cli-darwin-x64": "0.5.82",
25
+ "@team-agent/cli-linux-x64": "0.5.82"
26
26
  },
27
27
  "scripts": {
28
28
  "postinstall": "node npm/bincheck.mjs",