From c768c0cc1b06b7c48e30e2c3ffed5e3ea84eab35 Mon Sep 17 00:00:00 2001 From: Christian Luciani Date: Wed, 29 Jul 2026 12:53:50 -0500 Subject: [PATCH] feat(agents): enable ACP builtin agents for team mode via CLI fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove team_capable_override:false from all builtin ACP agents so runtime inference (is_team_capable -> supports_team_cli_fallback) decides team eligibility instead of a blanket block. Migrations 023, 025, and 029 seed all external ACP agents with team_capable_override:false as a conservative default. This blocks every one of them from joining teams, even when they don't declare shell:false or cli:false in their handshake — meaning the CLI fallback path (which injects $AIONUI_HELPER_BIN and describes team tools as shell commands) would naturally work. The correct gate is the runtime inference: - supports_team_mcp() for agents with MCP transport - supports_team_cli_fallback() for agents that can run shell Removing the override for all builtin ACP agents lets each agent's actual capabilities decide. Agents that later gain MCP support will automatically use the richer Mcp transport. Ref: https://github.com/iOfficeAI/AionCore/issues/718 --- crates/aionui-ai-agent/src/registry.rs | 2 +- ...1_enable_acp_builtin_team_cli_fallback.sql | 23 +++++++++++++++++++ .../aionui-db/tests/pi_acp_agent_migration.rs | 5 +++- .../tests/registry_binary_agents_migration.rs | 5 +++- .../tests/registry_npx_agents_migration.rs | 5 +++- 5 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 crates/aionui-db/migrations/031_enable_acp_builtin_team_cli_fallback.sql diff --git a/crates/aionui-ai-agent/src/registry.rs b/crates/aionui-ai-agent/src/registry.rs index 4ac21bb4e..7e167efe7 100644 --- a/crates/aionui-ai-agent/src/registry.rs +++ b/crates/aionui-ai-agent/src/registry.rs @@ -1631,7 +1631,7 @@ mod tests { assert_eq!(pi.agent_source_info.binary_name.as_deref(), Some("pi")); assert_eq!(pi.agent_source_info.bridge_binary.as_deref(), Some("npx")); assert_eq!(pi.native_skills_dirs.as_deref(), Some(&[".pi/skills".to_owned()][..])); - assert!(!pi.team_capable); + assert!(pi.team_capable); assert_eq!(pi.yolo_id, None); assert_eq!( pi.handshake diff --git a/crates/aionui-db/migrations/031_enable_acp_builtin_team_cli_fallback.sql b/crates/aionui-db/migrations/031_enable_acp_builtin_team_cli_fallback.sql new file mode 100644 index 000000000..1e4b99a9f --- /dev/null +++ b/crates/aionui-db/migrations/031_enable_acp_builtin_team_cli_fallback.sql @@ -0,0 +1,23 @@ +-- Let the runtime infer team capability for all builtin ACP agents +-- instead of blocking them with a blanket team_capable_override:false. +-- +-- Migrations 023 (Pi), 025 (ACP Registry npx + binary agents), and 029 +-- (Mimo Code) all seed behavior_policy with team_capable_override:false +-- as a conservative default. This blocks every external ACP agent from +-- joining teams, even when supports_team_cli_fallback() would naturally +-- return true for agents that don't declare shell:false or cli:false in +-- their handshake. +-- +-- The correct gate is the runtime inference in is_team_capable(): +-- ─ supports_team_mcp() for agents with MCP transport (stdio/http) +-- ─ supports_team_cli_fallback() for agents that can execute shell +-- commands (true unless caps explicitly disable shell/cli) +-- +-- Removing the override lets each agent's actual capabilities decide. +-- Agents that later gain MCP support will automatically use the richer +-- Mcp transport via team_tool_transport(). +UPDATE agent_metadata +SET behavior_policy = json_remove(behavior_policy, '$.team_capable_override'), + updated_at = unixepoch('now','subsec') * 1000 +WHERE agent_source = 'builtin' + AND agent_type = 'acp'; diff --git a/crates/aionui-db/tests/pi_acp_agent_migration.rs b/crates/aionui-db/tests/pi_acp_agent_migration.rs index c664a6136..537009f8b 100644 --- a/crates/aionui-db/tests/pi_acp_agent_migration.rs +++ b/crates/aionui-db/tests/pi_acp_agent_migration.rs @@ -22,7 +22,10 @@ async fn pi_acp_builtin_metadata_is_seeded() { let behavior_policy: serde_json::Value = serde_json::from_str(pi.behavior_policy.as_deref().expect("seeded behavior policy")).unwrap(); - assert_eq!(behavior_policy["team_capable_override"], false); + assert!( + behavior_policy.get("team_capable_override").is_none(), + "team_capable_override should be absent (removed by migration 031)" + ); let capabilities: serde_json::Value = serde_json::from_str(pi.agent_capabilities.as_deref().expect("seeded capabilities")).unwrap(); diff --git a/crates/aionui-db/tests/registry_binary_agents_migration.rs b/crates/aionui-db/tests/registry_binary_agents_migration.rs index 2c9e85f80..879ddaf0d 100644 --- a/crates/aionui-db/tests/registry_binary_agents_migration.rs +++ b/crates/aionui-db/tests/registry_binary_agents_migration.rs @@ -28,6 +28,9 @@ async fn verified_registry_binary_agents_store_stable_registry_identity() { assert!(source.get("distribution").is_none()); assert!(source.get("version").is_none()); let policy: serde_json::Value = serde_json::from_str(row.behavior_policy.as_deref().unwrap()).unwrap(); - assert_eq!(policy["team_capable_override"], false); + assert!( + policy.get("team_capable_override").is_none(), + "{backend} team_capable_override should be absent" + ); } } diff --git a/crates/aionui-db/tests/registry_npx_agents_migration.rs b/crates/aionui-db/tests/registry_npx_agents_migration.rs index c32b360d2..be5bda1ff 100644 --- a/crates/aionui-db/tests/registry_npx_agents_migration.rs +++ b/crates/aionui-db/tests/registry_npx_agents_migration.rs @@ -73,6 +73,9 @@ async fn verified_registry_npx_agents_use_stable_packages_and_conservative_team_ assert_eq!(source["binary_name"], binary_name, "{backend} binary_name"); assert_eq!(source["bridge_binary"], "npx", "{backend} bridge_binary"); let policy: serde_json::Value = serde_json::from_str(row.behavior_policy.as_deref().unwrap()).unwrap(); - assert_eq!(policy["team_capable_override"], false, "{backend} team policy"); + assert!( + policy.get("team_capable_override").is_none(), + "{backend} team_capable_override should be absent" + ); } }