1111from pydantic_ai .capabilities import AbstractCapability , AgentCapability
1212from pydantic_ai_skills import SkillsCapability
1313
14+ from configuration import AppConfig
1415from models .common .responses .responses_api_params import ResponsesApiParams
1516from models .common .tools import CatalogTool , CatalogToolParameter
16- from models .config import SkillsConfiguration
17+ from models .config import (
18+ QuestionValidityConfig ,
19+ RedactionConfig ,
20+ ShieldConfiguration ,
21+ SkillsConfiguration ,
22+ )
23+ from pydantic_ai_lightspeed .capabilities import QuestionValidity
24+ from pydantic_ai_lightspeed .capabilities .redaction import PiiRedactionCapability
1725from pydantic_ai_lightspeed .llamastack import (
1826 OgxResponsesModel ,
1927)
28+ from utils .shields import get_shields_for_request
2029
2130_AGENT_SKILLS_PROVIDER_ID : Final [str ] = "agent-skills"
2231_AGENT_SKILLS_TOOLGROUP_ID : Final [str ] = "builtin::agent-skills"
@@ -127,20 +136,51 @@ def get_agent_capability_tools(
127136 return tools
128137
129138
139+ def _shield_capability (shield : ShieldConfiguration ) -> AgentCapability [object ]:
140+ """Build the pydantic-ai capability instance for a single configured shield.
141+
142+ Parameters:
143+ shield: A single guardrail shield configuration entry.
144+
145+ Returns:
146+ A ``QuestionValidity`` capability when ``shield.provider_id`` is
147+ ``"question_validity"``, or a ``PiiRedactionCapability`` when it is
148+ ``"redaction"``.
149+
150+ Raises:
151+ ValueError: If ``shield.config`` doesn't match a known shield config type.
152+ """
153+ match shield .config :
154+ case QuestionValidityConfig ():
155+ return QuestionValidity (config = shield .config )
156+ case RedactionConfig ():
157+ return PiiRedactionCapability (config = shield .config )
158+ case _:
159+ raise ValueError (
160+ f"Unsupported shield config type for shield '{ shield .name } ': "
161+ f"{ type (shield .config ).__name__ } "
162+ )
163+
164+
130165def _agent_capabilities (
131166 skills : Optional [SkillsConfiguration ],
167+ shields : Optional [list [ShieldConfiguration ]] = None ,
132168 no_tools : bool = False ,
133169) -> Optional [list [AgentCapability [object ]]]:
134170 """Assemble pydantic-ai capabilities for an LCS agent.
135171
136172 Args:
137173 skills: Agent skills configuration from LCS, or None when skills are disabled.
174+ shields: Configured guardrail shields (question validity, redaction), or
175+ None/empty when no shields are enabled.
138176 no_tools: When True, omit capabilities that expose a toolset via ``get_toolset()``.
139177
140178 Returns:
141179 Configured capabilities, or None when no capabilities are enabled.
142180 """
143181 capabilities : list [AgentCapability [object ]] = []
182+ for shield in shields or []:
183+ capabilities .append (_shield_capability (shield ))
144184 if skills_capability := _skills_capability (skills ):
145185 capabilities .append (skills_capability )
146186 if no_tools :
@@ -158,7 +198,8 @@ def _agent_capabilities(
158198def build_agent (
159199 client : AsyncOgxClient | AsyncOGXAsLibraryClient ,
160200 responses_params : ResponsesApiParams ,
161- skills : Optional [SkillsConfiguration ],
201+ config : AppConfig ,
202+ shields : Optional [list [str ]] = None ,
162203 no_tools : bool = False ,
163204) -> Agent [None , str ]:
164205 """Build a Pydantic AI agent that mirrors ``responses_params`` on the Llama Stack backend.
@@ -171,14 +212,20 @@ def build_agent(
171212 Parameters:
172213 client: Initialized Llama Stack client from ``AsyncOgxClientHolder().get_client()``.
173214 responses_params: Parameters produced by ``prepare_responses_params`` for this turn.
174- skills: Agent skills configuration from LCS, or None when skills are disabled.
215+ config: Application configuration. Agent skills (``config.skills``) and the
216+ configured guardrail shields (``config.shields``) are extracted from it.
217+ shields: Optional list of shield names to run for this turn, matching each
218+ shield's configured ``name``. Mirrors ``QueryRequest.shield_ids``: if
219+ ``None``, all shields configured in ``config.shields`` run; an empty
220+ list disables all shields.
175221 no_tools: When True, omit capabilities that expose a toolset via ``get_toolset()``.
176222
177223 Returns:
178224 ``Agent`` configured for ``await agent.run(...)`` (or streaming) against the same
179225 stack configuration as ``client.responses.create(**responses_params.model_dump())``.
180226 """
181- capabilities = _agent_capabilities (skills , no_tools = no_tools )
227+ shield_configs = get_shields_for_request (config .shields , shields )
228+ capabilities = _agent_capabilities (config .skills , shield_configs , no_tools = no_tools )
182229
183230 model = OgxResponsesModel .from_ogx_client (
184231 responses_params .model , client , responses_params = responses_params
0 commit comments