@@ -661,6 +661,9 @@ fn stub_agent_metadata_rows() -> Vec<AgentMetadataRow> {
661661 ( "8e1acf31" , Some ( "codex" ) , "acp" , "Codex CLI" , 110 ) ,
662662 ( "cc126dd5" , Some ( "gemini" ) , "acp" , "Gemini CLI" , 120 ) ,
663663 ( "632f31d2" , None , "aionrs" , "Aion CLI" , 200 ) ,
664+ ( "b7e8a9c4" , Some ( "openclaw" ) , "acp" , "OpenClaw" , 3140 ) ,
665+ ( "f9f61666" , None , "openclaw-gateway" , "OpenClaw Gateway" , 3150 ) ,
666+ ( "custom-acp-1" , None , "acp" , "My Custom ACP" , 1500 ) ,
664667 ]
665668 . into_iter ( )
666669 . map ( |( id, backend, agent_type, name, sort_order) | AgentMetadataRow {
@@ -672,7 +675,7 @@ fn stub_agent_metadata_rows() -> Vec<AgentMetadataRow> {
672675 description_i18n : None ,
673676 backend : backend. map ( ToOwned :: to_owned) ,
674677 agent_type : agent_type. to_owned ( ) ,
675- agent_source : " builtin". to_owned ( ) ,
678+ agent_source : if id . starts_with ( "custom-" ) { "custom" } else { " builtin" } . to_owned ( ) ,
676679 agent_source_info : None ,
677680 enabled : true ,
678681 command : backend. map ( ToOwned :: to_owned) ,
@@ -1530,6 +1533,203 @@ async fn create_derives_acp_type_from_assistant_backend_when_type_is_missing() {
15301533 assert ! ( repo. get_assistant_snapshot( & resp. id) . await . unwrap( ) . is_some( ) ) ;
15311534}
15321535
1536+ #[ tokio:: test]
1537+ async fn create_derives_acp_type_from_openclaw_agent_metadata_when_type_is_missing ( ) {
1538+ let resolver = Arc :: new ( FixedSkillResolver { names : vec ! [ ] } ) ;
1539+ let dispatcher = Arc :: new ( StaticAssistantDispatcher {
1540+ rules : std:: collections:: HashMap :: new ( ) ,
1541+ } ) ;
1542+ let ( svc, _broadcaster, repo, definition_repo, overlay_repo, _preference_repo) =
1543+ make_service_with_assistant_support ( resolver, dispatcher) . await ;
1544+
1545+ upsert_test_assistant_definition (
1546+ & definition_repo,
1547+ "asstdef_openclaw_missing_type" ,
1548+ "assistant-openclaw-missing-type" ,
1549+ "b7e8a9c4" ,
1550+ "auto" ,
1551+ "auto" ,
1552+ )
1553+ . await ;
1554+ overlay_repo
1555+ . upsert ( & UpsertAssistantOverlayParams {
1556+ assistant_definition_id : "asstdef_openclaw_missing_type" ,
1557+ enabled : true ,
1558+ sort_order : 0 ,
1559+ agent_id_override : None ,
1560+ last_used_at : None ,
1561+ } )
1562+ . await
1563+ . unwrap ( ) ;
1564+
1565+ let workspace = ensure_test_workspace_path ( ) ;
1566+ let req: CreateConversationRequest = serde_json:: from_value ( json ! ( {
1567+ "assistant" : {
1568+ "id" : "assistant-openclaw-missing-type" ,
1569+ "locale" : "en-US"
1570+ } ,
1571+ "extra" : {
1572+ "workspace" : workspace
1573+ }
1574+ } ) )
1575+ . unwrap ( ) ;
1576+
1577+ let resp = svc. create ( "user_1" , req) . await . unwrap ( ) ;
1578+ assert_eq ! ( resp. r#type, AgentType :: Acp ) ;
1579+ assert_eq ! ( resp. extra[ "agent_id" ] , json!( "b7e8a9c4" ) ) ;
1580+ assert_eq ! ( resp. extra[ "backend" ] , json!( "openclaw" ) ) ;
1581+ assert ! ( repo. get_assistant_snapshot( & resp. id) . await . unwrap( ) . is_some( ) ) ;
1582+ }
1583+
1584+ #[ tokio:: test]
1585+ async fn create_derives_acp_type_from_custom_agent_metadata_when_type_is_missing ( ) {
1586+ let resolver = Arc :: new ( FixedSkillResolver { names : vec ! [ ] } ) ;
1587+ let dispatcher = Arc :: new ( StaticAssistantDispatcher {
1588+ rules : std:: collections:: HashMap :: new ( ) ,
1589+ } ) ;
1590+ let ( svc, _broadcaster, repo, definition_repo, overlay_repo, _preference_repo) =
1591+ make_service_with_assistant_support ( resolver, dispatcher) . await ;
1592+
1593+ upsert_test_assistant_definition (
1594+ & definition_repo,
1595+ "asstdef_custom_acp_missing_type" ,
1596+ "assistant-custom-acp-missing-type" ,
1597+ "custom-acp-1" ,
1598+ "auto" ,
1599+ "auto" ,
1600+ )
1601+ . await ;
1602+ overlay_repo
1603+ . upsert ( & UpsertAssistantOverlayParams {
1604+ assistant_definition_id : "asstdef_custom_acp_missing_type" ,
1605+ enabled : true ,
1606+ sort_order : 0 ,
1607+ agent_id_override : None ,
1608+ last_used_at : None ,
1609+ } )
1610+ . await
1611+ . unwrap ( ) ;
1612+
1613+ let workspace = ensure_test_workspace_path ( ) ;
1614+ let req: CreateConversationRequest = serde_json:: from_value ( json ! ( {
1615+ "assistant" : {
1616+ "id" : "assistant-custom-acp-missing-type" ,
1617+ "locale" : "en-US"
1618+ } ,
1619+ "extra" : {
1620+ "workspace" : workspace
1621+ }
1622+ } ) )
1623+ . unwrap ( ) ;
1624+
1625+ let resp = svc. create ( "user_1" , req) . await . unwrap ( ) ;
1626+ assert_eq ! ( resp. r#type, AgentType :: Acp ) ;
1627+ assert_eq ! ( resp. extra[ "agent_id" ] , json!( "custom-acp-1" ) ) ;
1628+ assert_eq ! ( resp. extra[ "agent_source" ] , json!( "custom" ) ) ;
1629+ assert_eq ! ( resp. extra[ "backend" ] , json!( "acp" ) ) ;
1630+ assert ! ( repo. get_assistant_snapshot( & resp. id) . await . unwrap( ) . is_some( ) ) ;
1631+ }
1632+
1633+ #[ tokio:: test]
1634+ async fn create_rejects_assistant_bound_to_deprecated_agent_metadata ( ) {
1635+ let resolver = Arc :: new ( FixedSkillResolver { names : vec ! [ ] } ) ;
1636+ let dispatcher = Arc :: new ( StaticAssistantDispatcher {
1637+ rules : std:: collections:: HashMap :: new ( ) ,
1638+ } ) ;
1639+ let ( svc, _broadcaster, _repo, definition_repo, overlay_repo, _preference_repo) =
1640+ make_service_with_assistant_support ( resolver, dispatcher) . await ;
1641+
1642+ upsert_test_assistant_definition (
1643+ & definition_repo,
1644+ "asstdef_openclaw_gateway_deprecated" ,
1645+ "assistant-openclaw-gateway-deprecated" ,
1646+ "f9f61666" ,
1647+ "auto" ,
1648+ "auto" ,
1649+ )
1650+ . await ;
1651+ overlay_repo
1652+ . upsert ( & UpsertAssistantOverlayParams {
1653+ assistant_definition_id : "asstdef_openclaw_gateway_deprecated" ,
1654+ enabled : true ,
1655+ sort_order : 0 ,
1656+ agent_id_override : None ,
1657+ last_used_at : None ,
1658+ } )
1659+ . await
1660+ . unwrap ( ) ;
1661+
1662+ let workspace = ensure_test_workspace_path ( ) ;
1663+ let req: CreateConversationRequest = serde_json:: from_value ( json ! ( {
1664+ "assistant" : {
1665+ "id" : "assistant-openclaw-gateway-deprecated" ,
1666+ "locale" : "en-US"
1667+ } ,
1668+ "extra" : {
1669+ "workspace" : workspace
1670+ }
1671+ } ) )
1672+ . unwrap ( ) ;
1673+
1674+ let err = svc. create ( "user_1" , req) . await . unwrap_err ( ) ;
1675+ assert_eq ! ( err. error_code( ) , "BAD_REQUEST" ) ;
1676+ assert ! (
1677+ err. to_string( )
1678+ . contains( "This agent type is no longer supported for new conversations." ) ,
1679+ "unexpected error: {err}"
1680+ ) ;
1681+ }
1682+
1683+ #[ tokio:: test]
1684+ async fn create_rejects_assistant_with_unregistered_agent_metadata ( ) {
1685+ let resolver = Arc :: new ( FixedSkillResolver { names : vec ! [ ] } ) ;
1686+ let dispatcher = Arc :: new ( StaticAssistantDispatcher {
1687+ rules : std:: collections:: HashMap :: new ( ) ,
1688+ } ) ;
1689+ let ( svc, _broadcaster, _repo, definition_repo, overlay_repo, _preference_repo) =
1690+ make_service_with_assistant_support ( resolver, dispatcher) . await ;
1691+
1692+ upsert_test_assistant_definition (
1693+ & definition_repo,
1694+ "asstdef_missing_agent" ,
1695+ "assistant-missing-agent" ,
1696+ "missing-agent" ,
1697+ "auto" ,
1698+ "auto" ,
1699+ )
1700+ . await ;
1701+ overlay_repo
1702+ . upsert ( & UpsertAssistantOverlayParams {
1703+ assistant_definition_id : "asstdef_missing_agent" ,
1704+ enabled : true ,
1705+ sort_order : 0 ,
1706+ agent_id_override : None ,
1707+ last_used_at : None ,
1708+ } )
1709+ . await
1710+ . unwrap ( ) ;
1711+
1712+ let workspace = ensure_test_workspace_path ( ) ;
1713+ let req: CreateConversationRequest = serde_json:: from_value ( json ! ( {
1714+ "assistant" : {
1715+ "id" : "assistant-missing-agent" ,
1716+ "locale" : "en-US"
1717+ } ,
1718+ "extra" : {
1719+ "workspace" : workspace
1720+ }
1721+ } ) )
1722+ . unwrap ( ) ;
1723+
1724+ let err = svc. create ( "user_1" , req) . await . unwrap_err ( ) ;
1725+ assert_eq ! ( err. error_code( ) , "BAD_REQUEST" ) ;
1726+ assert ! (
1727+ err. to_string( )
1728+ . contains( "assistant agent `missing-agent` is not registered in agent_metadata" ) ,
1729+ "unexpected error: {err}"
1730+ ) ;
1731+ }
1732+
15331733// ── Get tests ──────────────────────────────────────────────────────
15341734
15351735#[ tokio:: test]
0 commit comments