@@ -117,6 +117,38 @@ def setup_azure_entra_id_token(
117117# =============================================================================
118118
119119
120+ def _dedupe_vector_io_list (entries : list [Any ]) -> list [dict [str , Any ]]:
121+ """Keep the first dict per stripped ``provider_id``; keep entries without an id."""
122+ seen : set [str ] = set ()
123+ out : list [dict [str , Any ]] = []
124+ for item in entries :
125+ if not isinstance (item , dict ):
126+ continue
127+ raw_pid = item .get ("provider_id" )
128+ if raw_pid is None :
129+ out .append (item )
130+ continue
131+ key = str (raw_pid ).strip ()
132+ if not key :
133+ out .append (item )
134+ continue
135+ if key in seen :
136+ continue
137+ seen .add (key )
138+ out .append (item )
139+ return out
140+
141+
142+ def dedupe_providers_vector_io (ls_config : dict [str , Any ]) -> None :
143+ """Collapse ``providers.vector_io`` to one entry per ``provider_id``."""
144+ if "providers" not in ls_config or "vector_io" not in ls_config ["providers" ]:
145+ return
146+ raw = ls_config ["providers" ]["vector_io" ]
147+ if not isinstance (raw , list ):
148+ return
149+ ls_config ["providers" ]["vector_io" ] = _dedupe_vector_io_list (raw )
150+
151+
120152def construct_storage_backends_section (
121153 ls_config : dict [str , Any ], byok_rag : list [dict [str , Any ]]
122154) -> dict [str , Any ]:
@@ -312,19 +344,32 @@ def construct_vector_io_providers_section(
312344 `provider_type` set from the RAG item, and a `config` with `persistence`
313345 referencing the corresponding backend.
314346 """
315- output = []
347+ output : list [ dict [ str , Any ]] = []
316348
317- # fill-in existing vector_io entries
318349 if "providers" in ls_config and "vector_io" in ls_config ["providers" ]:
319- output = ls_config ["providers" ]["vector_io" ].copy ()
350+ raw = ls_config ["providers" ]["vector_io" ]
351+ if isinstance (raw , list ):
352+ output = _dedupe_vector_io_list (raw )
353+ else :
354+ output = []
355+
356+ existing_ids = {
357+ str (p ["provider_id" ]).strip ()
358+ for p in output
359+ if p .get ("provider_id" ) is not None and str (p ["provider_id" ]).strip ()
360+ }
320361
321- # append new vector_io entries
362+ added = 0
322363 for brag in byok_rag :
323364 if not brag .get ("rag_id" ):
324365 raise ValueError (f"BYOK RAG entry is missing required 'rag_id': { brag } " )
325- rag_id = brag ["rag_id" ]
366+ rag_id = str ( brag ["rag_id" ]). strip ()
326367 backend_name = f"byok_{ rag_id } _storage"
327368 provider_id = f"byok_{ rag_id } "
369+ if provider_id in existing_ids :
370+ continue
371+ existing_ids .add (provider_id )
372+ added += 1
328373 output .append (
329374 {
330375 "provider_id" : provider_id ,
@@ -339,7 +384,7 @@ def construct_vector_io_providers_section(
339384 )
340385 logger .info (
341386 "Added %s items into providers/vector_io section, total items %s" ,
342- len ( byok_rag ) ,
387+ added ,
343388 len (output ),
344389 )
345390 return output
@@ -354,6 +399,7 @@ def enrich_byok_rag(ls_config: dict[str, Any], byok_rag: list[dict[str, Any]]) -
354399 """
355400 if len (byok_rag ) == 0 :
356401 logger .info ("BYOK RAG is not configured: skipping" )
402+ dedupe_providers_vector_io (ls_config )
357403 return
358404
359405 logger .info ("Enriching Llama Stack config with BYOK RAG" )
@@ -567,6 +613,8 @@ def generate_configuration(
567613 with open (input_file , "r" , encoding = "utf-8" ) as file :
568614 ls_config = yaml .safe_load (file )
569615
616+ dedupe_providers_vector_io (ls_config )
617+
570618 # Enrichment: Azure Entra ID token
571619 setup_azure_entra_id_token (config .get ("azure_entra_id" ), env_file )
572620
@@ -576,6 +624,8 @@ def generate_configuration(
576624 # Enrichment: Solr - enabled when "okp" appears in either inline or tool list
577625 enrich_solr (ls_config , config .get ("rag" , {}), config .get ("okp" , {}))
578626
627+ dedupe_providers_vector_io (ls_config )
628+
579629 logger .info ("Writing Llama Stack configuration into file %s" , output_file )
580630
581631 with open (output_file , "w" , encoding = "utf-8" ) as file :
0 commit comments