@@ -648,21 +648,30 @@ def _catalog_operation_item(operation: Any) -> dict[str, Any]:
648648
649649
650650@lru_cache (maxsize = 1 )
651- def _manifest_scope_by_operation_id () -> dict [str , str ]:
651+ def _manifest_metadata_by_operation_id () -> dict [str , dict [ str , Any ] ]:
652652 try :
653653 raw = json .loads (CURATED_MANIFEST_PATH .read_text (encoding = "utf-8" ))
654654 except Exception :
655655 return {}
656656 if not isinstance (raw , list ):
657657 return {}
658658
659- scopes : dict [str , str ] = {}
659+ records : dict [str , dict [ str , Any ] ] = {}
660660 for item in raw :
661661 if not isinstance (item , Mapping ):
662662 continue
663663 operation_id = item .get ("operation_id" )
664- support_scope = item .get ("support_scope" )
665- if isinstance (operation_id , str ) and operation_id and isinstance (support_scope , str ):
664+ if not isinstance (operation_id , str ) or not operation_id :
665+ continue
666+ records [operation_id ] = dict (item )
667+ return records
668+
669+
670+ def _manifest_scope_by_operation_id () -> dict [str , str ]:
671+ scopes : dict [str , str ] = {}
672+ for operation_id , metadata in _manifest_metadata_by_operation_id ().items ():
673+ support_scope = metadata .get ("support_scope" )
674+ if isinstance (support_scope , str ):
666675 scopes [operation_id ] = support_scope
667676 return scopes
668677
@@ -685,17 +694,125 @@ def _apply_curated_manifest_filter(
685694 if not _should_use_curated_manifest (spec_file , public_only ):
686695 return operations
687696
688- manifest_scope = _manifest_scope_by_operation_id ()
689- if not manifest_scope :
697+ manifest_metadata = _manifest_metadata_by_operation_id ()
698+ if not manifest_metadata :
690699 return operations
691- allowed_operation_ids = set (manifest_scope )
700+ allowed_operation_ids = set (manifest_metadata )
692701 return [
693702 operation
694703 for operation in operations
695704 if getattr (operation , "operation_id" , None ) in allowed_operation_ids
696705 ]
697706
698707
708+ def _normalize_manifest_intents (value : Any ) -> set [str ]:
709+ intents : set [str ] = set ()
710+ if isinstance (value , str ):
711+ cleaned = value .strip ()
712+ if cleaned :
713+ intents .add (cleaned )
714+ return intents
715+ if isinstance (value , list ):
716+ for item in value :
717+ if isinstance (item , str ):
718+ cleaned = item .strip ()
719+ if cleaned :
720+ intents .add (cleaned )
721+ return intents
722+
723+
724+ def _collect_manifest_intents (metadata : Mapping [str , Any ]) -> set [str ]:
725+ intents = _normalize_manifest_intents (metadata .get ("intent" ))
726+ intents .update (_normalize_manifest_intents (metadata .get ("intents" )))
727+ return intents
728+
729+
730+ def _normalize_manifest_dependencies (value : Any ) -> tuple [str , ...]:
731+ dependencies : list [str ] = []
732+ if isinstance (value , list ):
733+ for item in value :
734+ if isinstance (item , str ) and item :
735+ dependencies .append (item )
736+ return tuple (sorted (set (dependencies )))
737+
738+
739+ def _infer_task_intents (task_terms : set [str ]) -> set [str ]:
740+ inferred : set [str ] = set ()
741+ if task_terms .intersection ({"agent" , "agents" , "assistant" }):
742+ inferred .add ("build_agent" )
743+ if task_terms .intersection ({"workflow" , "workflows" , "flow" , "automation" }):
744+ inferred .add ("build_workflow" )
745+ if task_terms .intersection ({"workforce" , "workforces" , "mas" , "team" }):
746+ inferred .add ("build_workforce" )
747+ if task_terms .intersection ({"run" , "execute" , "trigger" , "invoke" , "launch" }):
748+ inferred .add ("run" )
749+ if task_terms .intersection (
750+ {"debug" , "inspect" , "status" , "error" , "errors" , "trace" , "validate" , "diagnose" }
751+ ):
752+ inferred .add ("debug" )
753+ if "build" in task_terms and not inferred :
754+ inferred .add ("build_workflow" )
755+ return inferred
756+
757+
758+ def _intent_bonus_for_operation (
759+ operation_intents : set [str ],
760+ inferred_task_intents : set [str ],
761+ ) -> float :
762+ if not operation_intents or not inferred_task_intents :
763+ return 0.0
764+ if operation_intents .intersection (inferred_task_intents ):
765+ return 5.0
766+ return 0.0
767+
768+
769+ def _stage_bonus_for_operation (
770+ * ,
771+ stage : str | None ,
772+ task_terms : set [str ],
773+ inferred_task_intents : set [str ],
774+ ) -> float :
775+ if not stage :
776+ return 0.0
777+
778+ stage = stage .strip ().lower ()
779+ if not stage :
780+ return 0.0
781+
782+ wants_dependency_context = bool (
783+ task_terms .intersection (
784+ {"build" , "dependency" , "dependencies" , "configure" , "design" , "plan" }
785+ )
786+ )
787+ wants_apply = bool (task_terms .intersection ({"create" , "update" , "save" }))
788+
789+ if "run" in inferred_task_intents :
790+ if stage in {"apply" , "observe" }:
791+ return 2.0
792+ return 0.0
793+
794+ if "debug" in inferred_task_intents :
795+ if stage in {"observe" , "validate" }:
796+ return 2.0
797+ return 0.5 if stage == "discover" else 0.0
798+
799+ if inferred_task_intents .intersection ({"build_workflow" , "build_agent" , "build_workforce" }):
800+ if wants_dependency_context :
801+ return {
802+ "discover" : 2.5 ,
803+ "validate" : 2.0 ,
804+ "apply" : 1.0 ,
805+ "observe" : 0.5 ,
806+ }.get (stage , 0.0 )
807+ if wants_apply :
808+ return {
809+ "apply" : 2.0 ,
810+ "validate" : 1.0 ,
811+ "discover" : 0.5 ,
812+ }.get (stage , 0.0 )
813+ return 0.0
814+
815+
699816def _catalog_records (
700817 registry : OperationRegistry ,
701818 public_only : bool ,
@@ -779,11 +896,33 @@ def _rank_catalog_operations(
779896 max_cost : float | None = None ,
780897 max_latency_ms : float | None = None ,
781898 manifest_scope_by_operation_id : Mapping [str , str ] | None = None ,
899+ manifest_metadata_by_operation_id : Mapping [str , Mapping [str , Any ]] | None = None ,
782900) -> list [dict [str , Any ]]:
783901 task_terms = _tokenize_catalog_text (task )
784902 if not task_terms :
785903 return []
786904
905+ inferred_task_intents = _infer_task_intents (task_terms )
906+ wants_dependency_context = bool (
907+ task_terms .intersection (
908+ {
909+ "build" ,
910+ "builder" ,
911+ "create" ,
912+ "workflow" ,
913+ "workflows" ,
914+ "agent" ,
915+ "agents" ,
916+ "workforce" ,
917+ "dependency" ,
918+ "dependencies" ,
919+ "configure" ,
920+ "design" ,
921+ "plan" ,
922+ }
923+ )
924+ )
925+
787926 ranked : list [dict [str , Any ]] = []
788927 for operation in operations :
789928 operation_record = _catalog_operation_item (operation )
@@ -804,8 +943,15 @@ def _rank_catalog_operations(
804943 if max_latency_ms is not None and latency > max_latency_ms :
805944 continue
806945
946+ metadata = (
947+ manifest_metadata_by_operation_id .get (operation_record ["operation_id" ], {})
948+ if manifest_metadata_by_operation_id is not None
949+ else {}
950+ )
807951 support_scope = None
808- if manifest_scope_by_operation_id is not None :
952+ if isinstance (metadata .get ("support_scope" ), str ):
953+ support_scope = metadata ["support_scope" ]
954+ elif manifest_scope_by_operation_id is not None :
809955 support_scope = manifest_scope_by_operation_id .get (
810956 operation_record ["operation_id" ]
811957 )
@@ -815,21 +961,38 @@ def _rank_catalog_operations(
815961 elif support_scope == SUPPORT_SCOPE_BLOCKED :
816962 scope_bonus = 2.0
817963
964+ operation_intents = (
965+ _collect_manifest_intents (metadata )
966+ if isinstance (metadata , Mapping )
967+ else set ()
968+ )
969+ stage = metadata .get ("stage" ) if isinstance (metadata .get ("stage" ), str ) else None
970+ manifest_dependencies = (
971+ _normalize_manifest_dependencies (metadata .get ("dependencies" ))
972+ if isinstance (metadata , Mapping )
973+ else tuple ()
974+ )
975+ manifest_dependency_tokens = _tokenize_catalog_text (
976+ " " .join (manifest_dependencies )
977+ )
978+
979+ intent_bonus = _intent_bonus_for_operation (
980+ operation_intents ,
981+ inferred_task_intents ,
982+ )
983+ stage_bonus = _stage_bonus_for_operation (
984+ stage = stage ,
985+ task_terms = task_terms ,
986+ inferred_task_intents = inferred_task_intents ,
987+ )
988+
818989 dependency_bonus = 0.0
819- builder_terms = {
820- "build" ,
821- "builder" ,
822- "create" ,
823- "workflow" ,
824- "workflows" ,
825- "agent" ,
826- "agents" ,
827- "workforce" ,
828- "dependencies" ,
829- "dependency" ,
830- }
831- if task_terms .intersection (builder_terms ):
832- dependency_tokens = {
990+ if wants_dependency_context :
991+ if manifest_dependency_tokens :
992+ overlap = len (task_terms .intersection (manifest_dependency_tokens ))
993+ dependency_bonus += 1.0 + min (2.0 , float (overlap ))
994+
995+ heuristic_dependency_tokens = {
833996 "node" ,
834997 "nodes" ,
835998 "connection" ,
@@ -840,16 +1003,24 @@ def _rank_catalog_operations(
8401003 "templates" ,
8411004 "validate" ,
8421005 "schema" ,
1006+ "tool" ,
1007+ "tools" ,
1008+ "credential" ,
1009+ "credentials" ,
1010+ "integration" ,
1011+ "integrations" ,
8431012 }
844- dependency_bonus = float (
845- min (3 , len (operation_tokens .intersection (dependency_tokens )))
1013+ dependency_bonus + = float (
1014+ min (2 , len (operation_tokens .intersection (heuristic_dependency_tokens )))
8461015 )
8471016
8481017 score = round (
8491018 (relevance * 10 )
8501019 - cost
8511020 - (latency / 200 )
8521021 + scope_bonus
1022+ + intent_bonus
1023+ + stage_bonus
8531024 + dependency_bonus ,
8541025 3 ,
8551026 )
@@ -861,6 +1032,11 @@ def _rank_catalog_operations(
8611032 "estimated_latency_ms" : latency ,
8621033 "support_scope" : support_scope ,
8631034 "scope_bonus" : scope_bonus ,
1035+ "manifest_intents" : sorted (operation_intents ),
1036+ "manifest_stage" : stage ,
1037+ "manifest_dependencies" : list (manifest_dependencies ),
1038+ "intent_bonus" : intent_bonus ,
1039+ "stage_bonus" : stage_bonus ,
8641040 "dependency_bonus" : dependency_bonus ,
8651041 "score" : score ,
8661042 }
@@ -1607,17 +1783,18 @@ def _run_catalog_command(
16071783 public_only = args .public_only ,
16081784 spec_file = args .spec_file ,
16091785 )
1610- manifest_scope = (
1611- _manifest_scope_by_operation_id ()
1612- if _should_use_curated_manifest (args .spec_file , args .public_only )
1613- else None
1614- )
1786+ manifest_scope = None
1787+ manifest_metadata = None
1788+ if _should_use_curated_manifest (args .spec_file , args .public_only ):
1789+ manifest_scope = _manifest_scope_by_operation_id ()
1790+ manifest_metadata = _manifest_metadata_by_operation_id ( )
16151791 ranked = _rank_catalog_operations (
16161792 operations ,
16171793 task = args .task ,
16181794 max_cost = args .max_cost ,
16191795 max_latency_ms = args .max_latency_ms ,
16201796 manifest_scope_by_operation_id = manifest_scope ,
1797+ manifest_metadata_by_operation_id = manifest_metadata ,
16211798 )
16221799 if args .json :
16231800 payload = {
@@ -1629,7 +1806,10 @@ def _run_catalog_command(
16291806 "count" : len (ranked ),
16301807 "heuristic" : {
16311808 "name" : "relevance-cost-latency" ,
1632- "formula" : "score = relevance*10 - cost - latency/200" ,
1809+ "formula" : (
1810+ "score = relevance*10 - cost - latency/200 + "
1811+ "scope_bonus + intent_bonus + stage_bonus + dependency_bonus"
1812+ ),
16331813 },
16341814 "items" : ranked ,
16351815 }
@@ -2329,11 +2509,11 @@ def _run_code_search_command(
23292509 registry : OperationRegistry ,
23302510 sdk_client : AgenticFlowSDK ,
23312511) -> int :
2332- manifest_scope = (
2333- _manifest_scope_by_operation_id ()
2334- if _should_use_curated_manifest (args .spec_file , args .public_only )
2335- else None
2336- )
2512+ manifest_scope = None
2513+ manifest_metadata = None
2514+ if _should_use_curated_manifest (args .spec_file , args .public_only ):
2515+ manifest_scope = _manifest_scope_by_operation_id ()
2516+ manifest_metadata = _manifest_metadata_by_operation_id ( )
23372517 ranked = _rank_catalog_operations (
23382518 _catalog_operations (
23392519 registry ,
@@ -2344,6 +2524,7 @@ def _run_code_search_command(
23442524 max_cost = args .max_cost ,
23452525 max_latency_ms = args .max_latency_ms ,
23462526 manifest_scope_by_operation_id = manifest_scope ,
2527+ manifest_metadata_by_operation_id = manifest_metadata ,
23472528 )
23482529
23492530 if args .limit is not None and args .limit > 0 :
0 commit comments