@team-agent/installer 0.5.85 → 0.5.89
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 +2 -2
- package/crates/team-agent/src/cli/emit.rs +56 -12
- package/crates/team-agent/src/cli/mod.rs +0 -1
- package/crates/team-agent/src/cli/status_port/brief.rs +187 -7
- package/crates/team-agent/src/compiler/tests.rs +13 -24
- package/crates/team-agent/src/compiler.rs +5 -57
- package/crates/team-agent/src/leader/start.rs +0 -2
- package/crates/team-agent/src/lifecycle/launch/add_agent.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/agent_state.rs +0 -6
- package/crates/team-agent/src/lifecycle/launch/identity.rs +39 -22
- package/crates/team-agent/src/lifecycle/launch/layout.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/leader_context.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +0 -58
- package/crates/team-agent/src/lifecycle/launch/ownership.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +0 -3
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +14 -24
- package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/readiness.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/spawn.rs +5 -9
- package/crates/team-agent/src/lifecycle/launch/spec_state.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/state_projection.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch/worker_env.rs +0 -1
- package/crates/team-agent/src/lifecycle/launch.rs +0 -9
- package/crates/team-agent/src/lifecycle/restart/common.rs +5 -9
- package/crates/team-agent/src/lifecycle/tests/b0_reader_hideone_audit_contract.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +1 -3
- package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +42 -46
- package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +30 -44
- package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +32 -77
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +2 -13
- package/crates/team-agent/src/lifecycle/tests/pi_catalog_red.rs +0 -1
- package/crates/team-agent/src/lifecycle/tests/pi_command_red.rs +0 -2
- package/crates/team-agent/src/lifecycle/tests/pi_compiler_red.rs +14 -85
- package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +1 -1
- package/crates/team-agent/src/lifecycle/tests/pi_executable_mcp_red.rs +0 -5
- package/crates/team-agent/src/lifecycle/tests/pi_session_delivery_red.rs +0 -1
- package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +4 -4
- package/crates/team-agent/src/lifecycle/tests.rs +0 -1
- package/crates/team-agent/src/lifecycle/types.rs +0 -10
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +4 -248
- package/crates/team-agent/src/model/enums.rs +17 -38
- package/crates/team-agent/src/model/mod.rs +0 -1
- package/crates/team-agent/src/model/spec.rs +31 -91
- package/crates/team-agent/src/provider/adapter.rs +48 -50
- package/crates/team-agent/src/provider/adapters/claude.rs +5 -30
- package/crates/team-agent/src/provider/adapters/codex.rs +5 -25
- package/crates/team-agent/src/provider/adapters/copilot.rs +8 -41
- package/crates/team-agent/src/provider/adapters/cursor_agent.rs +4 -8
- package/crates/team-agent/src/provider/adapters/grok.rs +5 -58
- package/crates/team-agent/src/provider/adapters/mod.rs +5 -7
- package/crates/team-agent/src/provider/adapters/pi.rs +1 -56
- package/crates/team-agent/src/provider/bypass_flags.rs +1 -2
- package/crates/team-agent/src/provider/session/capture.rs +4 -4
- package/crates/team-agent/src/provider/tests/adapter.rs +7 -24
- package/crates/team-agent/src/provider/types.rs +1 -1
- package/crates/team-agent/src/provider/wire.rs +1 -1
- package/package.json +4 -4
- package/schemas/team.schema.json +4 -9
- package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +0 -784
- package/crates/team-agent/src/model/permissions.rs +0 -721
|
@@ -190,7 +190,7 @@ fn front_matter_non_object_errors() {
|
|
|
190
190
|
// separators=(",",":"))` with the workspace path templated to __WS__.
|
|
191
191
|
// (team-agent-public v0.2.11, /tmp/probe_compiler.py.)
|
|
192
192
|
|
|
193
|
-
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","
|
|
193
|
+
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","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},"dangerously_skip_permissions":false,"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"],"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"}]}"#;
|
|
194
194
|
|
|
195
195
|
#[test]
|
|
196
196
|
fn compile_base_noprofile_matches_python_dict_order_and_values() {
|
|
@@ -261,7 +261,7 @@ dangerously_skip_permissions: false
|
|
|
261
261
|
Implement bounded tasks.
|
|
262
262
|
";
|
|
263
263
|
|
|
264
|
-
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,"
|
|
264
|
+
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,"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},"dangerously_skip_permissions":false,"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"],"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"}]}"#;
|
|
265
265
|
|
|
266
266
|
#[test]
|
|
267
267
|
fn compile_runtime_front_matter_defaults_match_python() {
|
|
@@ -302,7 +302,7 @@ dangerously_skip_permissions: false
|
|
|
302
302
|
Edit and defend the argument.
|
|
303
303
|
";
|
|
304
304
|
|
|
305
|
-
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,"
|
|
305
|
+
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,"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},"dangerously_skip_permissions":false,"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"],"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"}]}"#;
|
|
306
306
|
|
|
307
307
|
#[test]
|
|
308
308
|
fn compile_provider_models_claude_code_falls_back_to_claude_alias() {
|
|
@@ -336,7 +336,7 @@ tools:
|
|
|
336
336
|
Implement bounded tasks.
|
|
337
337
|
";
|
|
338
338
|
|
|
339
|
-
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,"
|
|
339
|
+
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,"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},"dangerously_skip_permissions":false,"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"],"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"}]}"#;
|
|
340
340
|
|
|
341
341
|
#[test]
|
|
342
342
|
fn compile_subscription_without_model_uses_builtin_provider_default() {
|
|
@@ -378,7 +378,7 @@ tools:
|
|
|
378
378
|
Bravo body.
|
|
379
379
|
";
|
|
380
380
|
|
|
381
|
-
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","
|
|
381
|
+
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","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},"dangerously_skip_permissions":false,"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},"dangerously_skip_permissions":false,"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"],"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"}]}"#;
|
|
382
382
|
|
|
383
383
|
#[test]
|
|
384
384
|
fn compile_two_agents_sorted_by_filename_with_routing_and_startup_order() {
|
|
@@ -633,36 +633,25 @@ fn fix_a5_session_name_override_wins() {
|
|
|
633
633
|
// ── A6 tools ──
|
|
634
634
|
|
|
635
635
|
#[test]
|
|
636
|
-
fn
|
|
637
|
-
let role = "---\nname: w\nrole: R\nprovider: codex\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - shell\n -
|
|
636
|
+
fn fix_a6_tools_are_transparent_compatibility_metadata() {
|
|
637
|
+
let role = "---\nname: w\nrole: R\nprovider: codex\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools:\n - shell\n - provider_builtin\n---\nb\n";
|
|
638
638
|
let team = build_team(TM_CODEX, &[("w.md", role)], &[]);
|
|
639
|
-
let spec = compile_team(&team).expect("
|
|
640
|
-
|
|
641
|
-
agent0(&spec).get("tools"),
|
|
642
|
-
Some(&list_str(vec!["execute_bash", "mcp_team"]))
|
|
643
|
-
);
|
|
639
|
+
let spec = compile_team(&team).expect("tools metadata must not gate compilation");
|
|
640
|
+
assert!(agent0(&spec).get("tools").is_none());
|
|
644
641
|
}
|
|
645
642
|
|
|
646
643
|
#[test]
|
|
647
|
-
fn
|
|
644
|
+
fn fix_a6_missing_tools_is_allowed() {
|
|
648
645
|
let role = "---\nname: w\nrole: R\nprovider: codex\nauth_mode: subscription\ndangerously_skip_permissions: false\n---\nb\n";
|
|
649
646
|
let team = build_team(TM_CODEX, &[("w.md", role)], &[]);
|
|
650
|
-
|
|
651
|
-
assert!(
|
|
652
|
-
err.to_string().contains("missing front matter field tools"),
|
|
653
|
-
"got: {err}"
|
|
654
|
-
);
|
|
647
|
+
compile_team(&team).expect("omitted tools metadata must compile");
|
|
655
648
|
}
|
|
656
649
|
|
|
657
650
|
#[test]
|
|
658
|
-
fn
|
|
651
|
+
fn fix_a6_tools_non_list_is_transparent() {
|
|
659
652
|
let role = "---\nname: w\nrole: R\nprovider: codex\nauth_mode: subscription\ndangerously_skip_permissions: false\ntools: justastring\n---\nb\n";
|
|
660
653
|
let team = build_team(TM_CODEX, &[("w.md", role)], &[]);
|
|
661
|
-
|
|
662
|
-
assert!(
|
|
663
|
-
err.to_string().contains("tools must be a list"),
|
|
664
|
-
"got: {err}"
|
|
665
|
-
);
|
|
654
|
+
compile_team(&team).expect("any YAML tools metadata must compile");
|
|
666
655
|
}
|
|
667
656
|
|
|
668
657
|
// ── A7 system_prompt inline ──
|
|
@@ -30,11 +30,10 @@ use std::path::Path;
|
|
|
30
30
|
use crate::communication_mode::CommunicationMode;
|
|
31
31
|
use crate::model::enums::{Provider, ProviderEffort};
|
|
32
32
|
use crate::model::yaml::Value;
|
|
33
|
-
use crate::model::{paths,
|
|
34
|
-
use crate::provider::adapters::pi::first_unsupported_pi_tool_category;
|
|
33
|
+
use crate::model::{paths, spec, yaml, ModelError};
|
|
35
34
|
use crate::provider::wire::{
|
|
36
|
-
builtin_provider_model as wire_builtin_provider_model,
|
|
37
|
-
|
|
35
|
+
builtin_provider_model as wire_builtin_provider_model, parse_canonical_provider,
|
|
36
|
+
provider_model_keys,
|
|
38
37
|
};
|
|
39
38
|
|
|
40
39
|
pub const IGNORED_OWNER_TEAM_ID_FIELD: &str = "owner_team_id";
|
|
@@ -233,7 +232,6 @@ pub fn compile_team(team_dir: &Path) -> Result<Value, ModelError> {
|
|
|
233
232
|
("role", Value::Str(leader_role)),
|
|
234
233
|
("provider", Value::Str(leader_provider)),
|
|
235
234
|
("model", leader_model),
|
|
236
|
-
("tools", list_str(vec!["fs_read", "fs_list", "mcp_team"])),
|
|
237
235
|
(
|
|
238
236
|
"context_policy",
|
|
239
237
|
map(vec![
|
|
@@ -526,7 +524,6 @@ fn compile_role_agent_with_mode(
|
|
|
526
524
|
role_path.display(),
|
|
527
525
|
)));
|
|
528
526
|
}
|
|
529
|
-
let tools = required_tools(&meta, role_path)?;
|
|
530
527
|
let prompt_inline = non_empty_trimmed(&body).unwrap_or_else(|| role.clone());
|
|
531
528
|
let mut agent_items = vec![
|
|
532
529
|
("id", Value::Str(id.clone())),
|
|
@@ -542,7 +539,6 @@ fn compile_role_agent_with_mode(
|
|
|
542
539
|
("file", Value::Null),
|
|
543
540
|
]),
|
|
544
541
|
),
|
|
545
|
-
("tools", list_str(tools)),
|
|
546
542
|
// 0.5.66 bypass 单源:compiler 透传角色 md 的 `dangerously_skip_permissions`
|
|
547
543
|
// (必填 bool,spec 校验保证存在)。取代旧"恒发 permission_mode: restricted"。
|
|
548
544
|
(
|
|
@@ -606,12 +602,9 @@ fn compile_role_agent_with_mode(
|
|
|
606
602
|
})
|
|
607
603
|
.unwrap_or("");
|
|
608
604
|
let provider_enum = parse_canonical_provider(provider_str).unwrap_or(Provider::Codex);
|
|
609
|
-
if effort.
|
|
610
|
-
&& !is_claude_family(provider_enum)
|
|
611
|
-
&& provider_enum != Provider::Pi
|
|
612
|
-
{
|
|
605
|
+
if let Err(reason) = effort.resolve_for_provider(provider_enum) {
|
|
613
606
|
return Err(ModelError::Validation(format!(
|
|
614
|
-
"{}: effort
|
|
607
|
+
"{}: {reason} (effort: {}; provider: {provider_str})",
|
|
615
608
|
role_path.display(),
|
|
616
609
|
effort.as_str()
|
|
617
610
|
)));
|
|
@@ -758,25 +751,6 @@ fn validate_pi_role_fields(meta: &Value, path: &Path, provider: &str) -> Result<
|
|
|
758
751
|
)));
|
|
759
752
|
}
|
|
760
753
|
}
|
|
761
|
-
let tools = required_tools(meta, path)?;
|
|
762
|
-
if !tools.iter().any(|tool| tool == "mcp_team") {
|
|
763
|
-
return Err(ModelError::Validation(format!(
|
|
764
|
-
"{}: Pi roles require mcp_team",
|
|
765
|
-
path.display()
|
|
766
|
-
)));
|
|
767
|
-
}
|
|
768
|
-
let expanded = permissions::expand_tool_strings(tools.iter().map(String::as_str));
|
|
769
|
-
if let Some(category) = first_unsupported_pi_tool_category(
|
|
770
|
-
expanded
|
|
771
|
-
.iter()
|
|
772
|
-
.filter(|category| permissions::is_canonical_tool(category))
|
|
773
|
-
.map(String::as_str),
|
|
774
|
-
) {
|
|
775
|
-
return Err(ModelError::Validation(format!(
|
|
776
|
-
"{}: Pi does not support Team Agent tool category {category:?}; remove it from the role's tools",
|
|
777
|
-
path.display()
|
|
778
|
-
)));
|
|
779
|
-
}
|
|
780
754
|
Ok(())
|
|
781
755
|
}
|
|
782
756
|
|
|
@@ -876,32 +850,6 @@ fn py_int_value(value: &Value) -> Option<i64> {
|
|
|
876
850
|
}
|
|
877
851
|
}
|
|
878
852
|
|
|
879
|
-
fn required_tools(meta: &Value, path: &Path) -> Result<Vec<String>, ModelError> {
|
|
880
|
-
let Some(value) = meta.get("tools") else {
|
|
881
|
-
return Err(ModelError::Validation(format!(
|
|
882
|
-
"{}: missing front matter field tools",
|
|
883
|
-
path.display()
|
|
884
|
-
)));
|
|
885
|
-
};
|
|
886
|
-
let Some(items) = value.as_list() else {
|
|
887
|
-
return Err(ModelError::Validation(format!(
|
|
888
|
-
"{}: tools must be a list",
|
|
889
|
-
path.display()
|
|
890
|
-
)));
|
|
891
|
-
};
|
|
892
|
-
Ok(items
|
|
893
|
-
.iter()
|
|
894
|
-
.filter_map(Value::as_str)
|
|
895
|
-
.map(|tool| {
|
|
896
|
-
if tool == "shell" {
|
|
897
|
-
"execute_bash".to_string()
|
|
898
|
-
} else {
|
|
899
|
-
tool.to_string()
|
|
900
|
-
}
|
|
901
|
-
})
|
|
902
|
-
.collect())
|
|
903
|
-
}
|
|
904
|
-
|
|
905
853
|
fn resolve_model(role_meta: &Value, team_meta: &Value, provider: &str) -> Value {
|
|
906
854
|
if let Some(model) = string_field(role_meta, "model") {
|
|
907
855
|
return Value::Str(model);
|
|
@@ -304,7 +304,6 @@ fn leader_start_plan_with_ambient_authority(
|
|
|
304
304
|
identity.team_id.as_str(),
|
|
305
305
|
);
|
|
306
306
|
let prompt = crate::lifecycle::worker_command_context::compile_pi_leader_system_prompt();
|
|
307
|
-
let tools = ["mcp_team", "fs_read", "fs_list", "fs_write", "execute_bash"];
|
|
308
307
|
let team_mcp_tools = [
|
|
309
308
|
"assign_task",
|
|
310
309
|
"send_message",
|
|
@@ -327,7 +326,6 @@ fn leader_start_plan_with_ambient_authority(
|
|
|
327
326
|
model: parsed.model.as_deref(),
|
|
328
327
|
effort: parsed.effort,
|
|
329
328
|
system_prompt: &prompt,
|
|
330
|
-
tool_categories: &tools,
|
|
331
329
|
team_mcp_tools: &team_mcp_tools,
|
|
332
330
|
mcp_config: &mcp_config,
|
|
333
331
|
session_scope: crate::lifecycle::launch::pi_mcp::pi_leader_session_scope(
|
|
@@ -31,7 +31,6 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
|
|
31
31
|
use crate::lifecycle::*;
|
|
32
32
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
33
33
|
use crate::model::ids::AgentId;
|
|
34
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
35
34
|
use crate::model::yaml::{self, Value};
|
|
36
35
|
use crate::state::persist::load_runtime_state;
|
|
37
36
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -28,7 +28,6 @@ use std::process::Command;
|
|
|
28
28
|
use crate::lifecycle::*;
|
|
29
29
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
30
30
|
use crate::model::ids::AgentId;
|
|
31
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
32
31
|
use crate::model::yaml::{self, Value};
|
|
33
32
|
use crate::state::persist::load_runtime_state;
|
|
34
33
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -24,7 +24,6 @@ use std::process::Command;
|
|
|
24
24
|
use crate::lifecycle::*;
|
|
25
25
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
26
26
|
use crate::model::ids::AgentId;
|
|
27
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
28
27
|
use crate::model::yaml::{self, Value};
|
|
29
28
|
use crate::state::persist::load_runtime_state;
|
|
30
29
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -106,11 +105,6 @@ pub(super) fn running_agent_state(
|
|
|
106
105
|
"mcp_config".to_string(),
|
|
107
106
|
serde_json::json!(mcp_config_path.to_string_lossy().to_string()),
|
|
108
107
|
);
|
|
109
|
-
state.insert(
|
|
110
|
-
"permissions".to_string(),
|
|
111
|
-
permissions_json(agent, id, provider)
|
|
112
|
-
.map_err(|e| LifecycleError::Compile(e.to_string()))?,
|
|
113
|
-
);
|
|
114
108
|
// 0.5.66 bypass 单源:policy 从 agent 字段派生,不再用全队 `DangerousApproval`。
|
|
115
109
|
persist_effective_approval_policy_from_yaml_agent(&mut state, agent, provider);
|
|
116
110
|
// 0.5.66 bypass 单源 §2.6:fresh spawn 记录运行面 bypass 值(供 restart drift 挡板)。
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
//! - name: transport_has_session
|
|
10
10
|
//! what: 探测 tmux session 是否存在,探测本身出错一律当不存在
|
|
11
11
|
//! - name: provider_effort_from_raw
|
|
12
|
-
//! what: 解析 effort
|
|
12
|
+
//! what: 解析 effort,保留兼容忽略项并拒绝非法 provider 组合
|
|
13
13
|
//! - name: quick_start_depth_guard
|
|
14
14
|
//! what: 定出本次 quick-start 的父团队与层级,推不出父团队时拒绝
|
|
15
15
|
//! - name: annotate_persisted_team_depth
|
|
@@ -33,7 +33,6 @@ use std::process::Command;
|
|
|
33
33
|
use crate::lifecycle::*;
|
|
34
34
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
35
35
|
use crate::model::ids::AgentId;
|
|
36
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
37
36
|
use crate::model::yaml::{self, Value};
|
|
38
37
|
use crate::state::persist::load_runtime_state;
|
|
39
38
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -136,24 +135,24 @@ pub(super) fn parse_auth_mode(raw: &str) -> Option<AuthMode> {
|
|
|
136
135
|
/// purpose: 从原始字符串解析 effort,并要求当前 provider 支持它
|
|
137
136
|
/// params:
|
|
138
137
|
/// raw: effort 原文,None 或空白返回 None
|
|
139
|
-
/// returns:
|
|
138
|
+
/// returns: 支持的档位或兼容忽略的 None;已知非法 provider/effort 组合返回错误
|
|
140
139
|
/// ---
|
|
141
140
|
/// 0.4.x provider effort MVP step 4: low-level from a raw string. Returns
|
|
142
|
-
/// `Some(effort)`
|
|
141
|
+
/// `Some(effort)` for supported levels, None for legacy ignored values,
|
|
142
|
+
/// and an error for provider/effort combinations rejected by configuration.
|
|
143
143
|
pub(crate) fn provider_effort_from_raw(
|
|
144
144
|
raw: Option<&str>,
|
|
145
145
|
provider: Provider,
|
|
146
|
-
) -> Option<ProviderEffort> {
|
|
147
|
-
let
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
146
|
+
) -> Result<Option<ProviderEffort>, LifecycleError> {
|
|
147
|
+
let Some(effort) = raw.and_then(ProviderEffort::parse) else {
|
|
148
|
+
return Ok(None);
|
|
149
|
+
};
|
|
150
|
+
effort.resolve_for_provider(provider).map_err(|reason| {
|
|
151
|
+
LifecycleError::RequirementUnmet(format!(
|
|
152
|
+
"{reason} (effort: {}; provider: {provider:?})",
|
|
153
|
+
effort.as_str()
|
|
154
|
+
))
|
|
155
|
+
})
|
|
157
156
|
}
|
|
158
157
|
|
|
159
158
|
/// ---
|
|
@@ -172,7 +171,7 @@ pub(crate) fn provider_effort_event_payload(
|
|
|
172
171
|
return None;
|
|
173
172
|
}
|
|
174
173
|
let effort = ProviderEffort::parse(raw)?;
|
|
175
|
-
if effort.
|
|
174
|
+
if !matches!(effort.resolve_for_provider(provider), Ok(None)) {
|
|
176
175
|
return None;
|
|
177
176
|
}
|
|
178
177
|
Some(serde_json::json!({
|
|
@@ -222,7 +221,7 @@ pub(crate) fn extend_worker_env_unset_for_effort(
|
|
|
222
221
|
pub(crate) fn provider_effort_for_spawn(
|
|
223
222
|
agent: &crate::model::yaml::Value,
|
|
224
223
|
provider: Provider,
|
|
225
|
-
) -> Option<ProviderEffort> {
|
|
224
|
+
) -> Result<Option<ProviderEffort>, LifecycleError> {
|
|
226
225
|
provider_effort_from_raw(agent.get("effort").and_then(|v| v.as_str()), provider)
|
|
227
226
|
}
|
|
228
227
|
|
|
@@ -253,7 +252,7 @@ pub(crate) fn provider_effort_event_if_dropped(
|
|
|
253
252
|
pub(crate) fn provider_effort_for_spawn_json(
|
|
254
253
|
agent: &serde_json::Value,
|
|
255
254
|
provider: Provider,
|
|
256
|
-
) -> Option<ProviderEffort> {
|
|
255
|
+
) -> Result<Option<ProviderEffort>, LifecycleError> {
|
|
257
256
|
provider_effort_from_raw(
|
|
258
257
|
agent.get("effort").and_then(serde_json::Value::as_str),
|
|
259
258
|
provider,
|
|
@@ -308,10 +307,16 @@ pub(super) fn quick_start_depth_guard(
|
|
|
308
307
|
requested_team: Option<&str>,
|
|
309
308
|
_strict_real_runtime: bool,
|
|
310
309
|
) -> Result<QuickStartDepth, LifecycleError> {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
310
|
+
// OWNER_TEAM_ID is injected into every worker process. It is parent
|
|
311
|
+
// context only when the target quick-start workspace is the same workspace
|
|
312
|
+
// that produced the environment; otherwise a worker launching a fresh
|
|
313
|
+
// external workspace would inherit a false nesting parent.
|
|
314
|
+
let env_parent = owner_context_matches_workspace(workspace).then(|| {
|
|
315
|
+
std::env::var("TEAM_AGENT_OWNER_TEAM_ID")
|
|
316
|
+
.ok()
|
|
317
|
+
.map(|value| value.trim().to_string())
|
|
318
|
+
.filter(|value| !value.is_empty())
|
|
319
|
+
}).flatten();
|
|
315
320
|
let parent = env_parent;
|
|
316
321
|
let Some(parent) = parent else {
|
|
317
322
|
let state = crate::state::persist::load_runtime_state(workspace)
|
|
@@ -366,6 +371,18 @@ pub(super) fn quick_start_depth_guard(
|
|
|
366
371
|
/// purpose: 从 runtime state 推断父团队键
|
|
367
372
|
/// returns: 活跃团队键,且该团队确有 running 席位时返回它,否则 None
|
|
368
373
|
/// ---
|
|
374
|
+
fn owner_context_matches_workspace(workspace: &Path) -> bool {
|
|
375
|
+
let Some(env_workspace) = std::env::var_os("TEAM_AGENT_WORKSPACE") else {
|
|
376
|
+
return false;
|
|
377
|
+
};
|
|
378
|
+
let env_workspace = PathBuf::from(env_workspace);
|
|
379
|
+
env_workspace == workspace
|
|
380
|
+
|| std::fs::canonicalize(&env_workspace)
|
|
381
|
+
.ok()
|
|
382
|
+
.zip(std::fs::canonicalize(workspace).ok())
|
|
383
|
+
.is_some_and(|(env_path, target_path)| env_path == target_path)
|
|
384
|
+
}
|
|
385
|
+
|
|
369
386
|
pub(super) fn infer_parent_team_from_active_state(state: &serde_json::Value) -> Option<String> {
|
|
370
387
|
let active = explicit_active_team_key(state)?;
|
|
371
388
|
let team = state
|
|
@@ -25,7 +25,6 @@ use std::process::Command;
|
|
|
25
25
|
use crate::lifecycle::*;
|
|
26
26
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
27
27
|
use crate::model::ids::AgentId;
|
|
28
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
29
28
|
use crate::model::yaml::{self, Value};
|
|
30
29
|
use crate::state::persist::load_runtime_state;
|
|
31
30
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -31,7 +31,6 @@ use crate::lifecycle::profile_launch::parse_provider;
|
|
|
31
31
|
use crate::lifecycle::*;
|
|
32
32
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
33
33
|
use crate::model::ids::AgentId;
|
|
34
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
35
34
|
use crate::model::yaml::{self, Value};
|
|
36
35
|
use crate::state::persist::load_runtime_state;
|
|
37
36
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
//! what: 把 argv 里的 MCP 配置参数改指到已落盘的文件
|
|
17
17
|
//! depends:
|
|
18
18
|
//! - crate::provider::McpConfig
|
|
19
|
-
//! - crate::model::permissions
|
|
20
19
|
//! - crate::event_log::EventLog
|
|
21
20
|
//! - crate::lifecycle::profile_launch
|
|
22
21
|
//! - std::fs
|
|
@@ -33,8 +32,6 @@ use std::process::Command;
|
|
|
33
32
|
|
|
34
33
|
use crate::lifecycle::*;
|
|
35
34
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
36
|
-
use crate::model::ids::AgentId;
|
|
37
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
38
35
|
use crate::model::yaml::{self, Value};
|
|
39
36
|
use crate::state::persist::load_runtime_state;
|
|
40
37
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -644,58 +641,3 @@ pub(crate) fn point_native_mcp_config_at_file(
|
|
|
644
641
|
_ => {}
|
|
645
642
|
}
|
|
646
643
|
}
|
|
647
|
-
|
|
648
|
-
/// ---
|
|
649
|
-
/// purpose: 解析该席位的权限并序列化成 JSON
|
|
650
|
-
/// returns: 含 agent_id、provider、排序后的工具串、逐工具的执行强度与是否有仅提示项
|
|
651
|
-
/// errors: 权限解析失败时返回 ModelError
|
|
652
|
-
/// ---
|
|
653
|
-
pub(super) fn permissions_json(
|
|
654
|
-
agent: &Value,
|
|
655
|
-
id: &str,
|
|
656
|
-
provider: Provider,
|
|
657
|
-
) -> Result<serde_json::Value, crate::model::ModelError> {
|
|
658
|
-
let tools = agent.get("tools").and_then(Value::as_list).map(|items| {
|
|
659
|
-
items
|
|
660
|
-
.iter()
|
|
661
|
-
.filter_map(Value::as_str)
|
|
662
|
-
.map(str::to_string)
|
|
663
|
-
.collect::<Vec<_>>()
|
|
664
|
-
});
|
|
665
|
-
let resolved = permissions::resolve_permissions(&AgentPermissionInput {
|
|
666
|
-
id: Some(AgentId::new(id)),
|
|
667
|
-
provider,
|
|
668
|
-
role: agent
|
|
669
|
-
.get("role")
|
|
670
|
-
.and_then(Value::as_str)
|
|
671
|
-
.map(str::to_string),
|
|
672
|
-
tools,
|
|
673
|
-
})?;
|
|
674
|
-
let mut out = serde_json::Map::new();
|
|
675
|
-
out.insert("agent_id".to_string(), serde_json::json!(id));
|
|
676
|
-
out.insert("provider".to_string(), serde_json::json!(provider));
|
|
677
|
-
out.insert(
|
|
678
|
-
"tools".to_string(),
|
|
679
|
-
serde_json::json!(resolved.sorted_tool_strings()),
|
|
680
|
-
);
|
|
681
|
-
out.insert(
|
|
682
|
-
"resolved_tools".to_string(),
|
|
683
|
-
serde_json::Value::Array(
|
|
684
|
-
resolved
|
|
685
|
-
.resolved_tools
|
|
686
|
-
.iter()
|
|
687
|
-
.map(|tool| {
|
|
688
|
-
serde_json::json!({
|
|
689
|
-
"tool": tool.tool,
|
|
690
|
-
"enforcement": tool.enforcement,
|
|
691
|
-
})
|
|
692
|
-
})
|
|
693
|
-
.collect(),
|
|
694
|
-
),
|
|
695
|
-
);
|
|
696
|
-
out.insert(
|
|
697
|
-
"has_prompt_only".to_string(),
|
|
698
|
-
serde_json::json!(resolved.has_prompt_only),
|
|
699
|
-
);
|
|
700
|
-
Ok(serde_json::Value::Object(out))
|
|
701
|
-
}
|
|
@@ -25,7 +25,6 @@ use std::process::Command;
|
|
|
25
25
|
use crate::lifecycle::*;
|
|
26
26
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
27
27
|
use crate::model::ids::AgentId;
|
|
28
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
29
28
|
use crate::model::yaml::{self, Value};
|
|
30
29
|
use crate::state::persist::load_runtime_state;
|
|
31
30
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -995,7 +995,6 @@ pub(crate) struct PiMaterializeRequest<'a> {
|
|
|
995
995
|
pub model: Option<&'a str>,
|
|
996
996
|
pub effort: Option<ProviderEffort>,
|
|
997
997
|
pub system_prompt: &'a str,
|
|
998
|
-
pub tool_categories: &'a [&'a str],
|
|
999
998
|
pub team_mcp_tools: &'a [&'a str],
|
|
1000
999
|
pub mcp_config: &'a McpConfig,
|
|
1001
1000
|
pub session_scope: PiSessionScope,
|
|
@@ -1093,7 +1092,6 @@ fn materialize_pi_plan_with_session(
|
|
|
1093
1092
|
model: model.as_deref(),
|
|
1094
1093
|
effort: request.effort,
|
|
1095
1094
|
system_prompt: request.system_prompt,
|
|
1096
|
-
tool_categories: request.tool_categories,
|
|
1097
1095
|
session_dir,
|
|
1098
1096
|
session: PiSessionSelector::Resume { path: &exact_path },
|
|
1099
1097
|
agent_id: request.agent_id,
|
|
@@ -1106,7 +1104,6 @@ fn materialize_pi_plan_with_session(
|
|
|
1106
1104
|
model: model.as_deref(),
|
|
1107
1105
|
effort: request.effort,
|
|
1108
1106
|
system_prompt: request.system_prompt,
|
|
1109
|
-
tool_categories: request.tool_categories,
|
|
1110
1107
|
session_dir,
|
|
1111
1108
|
session: PiSessionSelector::Fresh {
|
|
1112
1109
|
session_id: session_id.as_str(),
|
|
@@ -31,7 +31,6 @@ use std::process::Command;
|
|
|
31
31
|
use crate::lifecycle::*;
|
|
32
32
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
33
33
|
use crate::model::ids::AgentId;
|
|
34
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
35
34
|
use crate::model::yaml::{self, Value};
|
|
36
35
|
use crate::state::persist::load_runtime_state;
|
|
37
36
|
use crate::transport::{PaneField, PaneId, SessionName, Target, Transport, WindowName};
|
|
@@ -4434,7 +4433,7 @@ mod fresh_quick_start_leader_binding_tests {
|
|
|
4434
4433
|
|
|
4435
4434
|
|
|
4436
4435
|
#[test]
|
|
4437
|
-
fn
|
|
4436
|
+
fn pi_tool_category_is_transparently_accepted_by_compiler() {
|
|
4438
4437
|
let root = std::env::temp_dir().join(format!(
|
|
4439
4438
|
"ta-quick-start-pi-tools-{}-{}",
|
|
4440
4439
|
std::process::id(),
|
|
@@ -4453,29 +4452,20 @@ mod fresh_quick_start_leader_binding_tests {
|
|
|
4453
4452
|
)
|
|
4454
4453
|
.unwrap();
|
|
4455
4454
|
|
|
4456
|
-
let
|
|
4457
|
-
|
|
4458
|
-
let
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
)
|
|
4468
|
-
.expect_err("invalid Pi category must fail before quick-start persistence");
|
|
4469
|
-
let error = error.to_string();
|
|
4470
|
-
assert!(error.contains("Pi does not support Team Agent tool category \"provider_builtin\""));
|
|
4471
|
-
assert!(error.contains("remove it from the role's tools"));
|
|
4472
|
-
assert!(
|
|
4473
|
-
!crate::state::persist::runtime_state_path(&root).exists(),
|
|
4474
|
-
"quick-start validation failure must not persist runtime state"
|
|
4475
|
-
);
|
|
4455
|
+
let spec = crate::compiler::compile_team(&team)
|
|
4456
|
+
.expect("tools metadata must be transparently accepted by the compiler");
|
|
4457
|
+
let worker = spec
|
|
4458
|
+
.get("agents")
|
|
4459
|
+
.and_then(Value::as_list)
|
|
4460
|
+
.and_then(|agents| {
|
|
4461
|
+
agents.iter().find(|agent| {
|
|
4462
|
+
agent.get("id").and_then(Value::as_str) == Some("worker")
|
|
4463
|
+
})
|
|
4464
|
+
})
|
|
4465
|
+
.expect("compiled spec must retain the worker role");
|
|
4476
4466
|
assert!(
|
|
4477
|
-
|
|
4478
|
-
"
|
|
4467
|
+
worker.get("tools").is_none(),
|
|
4468
|
+
"tools metadata must not acquire runtime semantics"
|
|
4479
4469
|
);
|
|
4480
4470
|
let _ = std::fs::remove_dir_all(root);
|
|
4481
4471
|
}
|
|
@@ -28,7 +28,6 @@ use std::process::Command;
|
|
|
28
28
|
use crate::lifecycle::*;
|
|
29
29
|
use crate::model::enums::{AuthMode, DisplayBackend, PaneLiveness, Provider, ProviderEffort};
|
|
30
30
|
use crate::model::ids::AgentId;
|
|
31
|
-
use crate::model::permissions::{self, AgentPermissionInput};
|
|
32
31
|
use crate::model::yaml::{self, Value};
|
|
33
32
|
use crate::state::persist::load_runtime_state;
|
|
34
33
|
use crate::transport::{PaneId, SessionName, Target, Transport, WindowName};
|