@@ -454,6 +454,54 @@ async def _get_package_doc(
454454}
455455
456456
457+ # Words to skip when building asset search patterns
458+ _ASSET_STOPWORDS = {
459+ "in" , "the" , "a" , "an" , "to" , "for" , "of" , "on" , "with" , "how" , "can" , "do" ,
460+ "i" , "my" , "is" , "it" , "this" , "that" , "unity" , "objects" , "object" , "using" ,
461+ "receive" , "make" , "apply" , "get" , "set" , "use" , "create" ,
462+ }
463+
464+ # Map keywords to Unity asset filter types
465+ _KEYWORD_TO_FILTER_TYPE = {
466+ "shader" : "Shader" , "shaders" : "Shader" , "lit" : "Shader" , "unlit" : "Shader" ,
467+ "material" : "Material" , "materials" : "Material" , "mat" : "Material" ,
468+ "texture" : "Texture2D" , "textures" : "Texture2D" , "tex" : "Texture2D" ,
469+ "sprite" : "Sprite" , "sprites" : "Sprite" ,
470+ "prefab" : "Prefab" , "prefabs" : "Prefab" ,
471+ "mesh" : "Mesh" , "model" : "Mesh" ,
472+ "font" : "Font" , "fonts" : "Font" ,
473+ }
474+
475+
476+ def _build_asset_search_terms (query : str ) -> list [dict [str , str ]]:
477+ """Extract meaningful search terms and infer asset filter types from query."""
478+ words = query .lower ().replace ("-" , " " ).replace ("_" , " " ).split ()
479+ terms = [w for w in words if w not in _ASSET_STOPWORDS and len (w ) > 1 ]
480+
481+ # Infer filter_type from keywords
482+ filter_type = None
483+ for w in words :
484+ if w in _KEYWORD_TO_FILTER_TYPE :
485+ filter_type = _KEYWORD_TO_FILTER_TYPE [w ]
486+ break
487+
488+ # Build search patterns: each non-stopword term as a separate search
489+ searches = []
490+ for term in terms :
491+ if term in _ASSET_KEYWORDS :
492+ continue # Skip generic keywords like "shader" — they're too broad
493+ params : dict [str , str ] = {"search_pattern" : f"*{ term } *" }
494+ if filter_type :
495+ params ["filter_type" ] = filter_type
496+ searches .append (params )
497+
498+ # If only keywords remain (e.g., "2D shader"), search by filter type alone
499+ if not searches and filter_type :
500+ searches .append ({"filter_type" : filter_type })
501+
502+ return searches
503+
504+
457505async def _search_assets (ctx : Any , query : str ) -> dict [str , Any ] | None :
458506 """Search Unity assets if ctx has a Unity connection. Returns None if unavailable."""
459507 try :
@@ -462,23 +510,43 @@ async def _search_assets(ctx: Any, query: str) -> dict[str, Any] | None:
462510 from transport .legacy .unity_connection import async_send_command_with_retry
463511
464512 unity_instance = await get_unity_instance_from_context (ctx )
465- result = await send_with_unity_instance (
466- async_send_command_with_retry ,
467- unity_instance ,
468- "manage_asset" ,
469- {"action" : "search" , "path" : "." , "search_pattern" : f"*{ query } *" , "pageSize" : 10 },
470- )
471- if isinstance (result , dict ) and result .get ("success" ):
472- assets = result .get ("data" , {}).get ("assets" , [])
473- if assets :
474- return {
475- "source" : "project_assets" ,
476- "found" : True ,
477- "assets" : [
478- {"name" : a .get ("name" , "" ), "path" : a .get ("path" , "" ), "type" : a .get ("assetType" , "" )}
479- for a in assets
480- ],
481- }
513+
514+ search_terms = _build_asset_search_terms (query )
515+ if not search_terms :
516+ return None
517+
518+ # Run all search terms in parallel
519+ all_assets = []
520+ seen_paths : set [str ] = set ()
521+
522+ async def _do_search (params : dict ) -> list [dict ]:
523+ search_params : dict [str , Any ] = {"action" : "search" , "path" : "." , "pageSize" : 10 }
524+ search_params .update (params )
525+ result = await send_with_unity_instance (
526+ async_send_command_with_retry , unity_instance , "manage_asset" , search_params ,
527+ )
528+ if isinstance (result , dict ) and result .get ("success" ):
529+ return result .get ("data" , {}).get ("assets" , [])
530+ return []
531+
532+ results = await asyncio .gather (* [_do_search (p ) for p in search_terms ], return_exceptions = True )
533+
534+ for result in results :
535+ if isinstance (result , list ):
536+ for a in result :
537+ path = a .get ("path" , "" )
538+ if path and path not in seen_paths :
539+ seen_paths .add (path )
540+ all_assets .append (
541+ {"name" : a .get ("name" , "" ), "path" : path , "type" : a .get ("assetType" , "" )}
542+ )
543+
544+ if all_assets :
545+ return {
546+ "source" : "project_assets" ,
547+ "found" : True ,
548+ "assets" : all_assets [:15 ], # Cap to avoid huge payloads
549+ }
482550 except Exception :
483551 pass # No Unity connection or import failure — skip silently
484552 return None
0 commit comments