Skip to content

Commit 32aac5d

Browse files
committed
Fix filter by name
1 parent 48f6b98 commit 32aac5d

5 files changed

Lines changed: 37 additions & 27 deletions

File tree

src/sap_cloud_sdk/agentgateway/_lob.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -478,27 +478,29 @@ async def get_agent_cards_lob(
478478
tenant_subdomain: str,
479479
system_token: str,
480480
timeout: float,
481-
names: list[str] | None = None,
481+
agent_names: list[str] | None = None,
482482
ord_ids: list[str] | None = None,
483483
) -> list[Agent]:
484484
"""List A2A agents and their agent cards using LoB flow.
485485
486-
Discovers A2A fragments (label agw.a2a.server), optionally filters them,
487-
then fetches the agent card for each from the fragment's URL property.
486+
Discovers A2A fragments (label agw.a2a.server), optionally filters by
487+
ORD ID before fetching, fetches each agent card, then optionally filters
488+
by agent card name.
488489
489490
Fragment properties used:
490491
URL: Base URL of the A2A agent (required).
491492
The agent card is fetched at {URL}/.well-known/agent-card.json.
492-
ordId: ORD ID of the A2A agent (required).
493+
The ORD ID is extracted from the second-to-last URL path segment.
493494
494495
Args:
495496
tenant_subdomain: Tenant subdomain for multi-tenant lookup.
496497
system_token: Pre-fetched raw system token for authentication.
497498
timeout: HTTP timeout in seconds.
498-
names: Optional list of fragment names to include. If empty or None,
499-
all fragments are included.
500-
ord_ids: Optional list of ORD IDs to include. If empty or None,
501-
all fragments are included.
499+
agent_names: Optional list of agent card names to include (matched
500+
against the `name` field in the fetched agent card JSON).
501+
Applied after fetching. If empty or None, all are included.
502+
ord_ids: Optional list of ORD IDs to include (extracted from URL).
503+
Applied before fetching. If empty or None, all are included.
502504
503505
Returns:
504506
List of Agent objects, each containing ORD ID and fetched AgentCard.
@@ -514,10 +516,7 @@ async def get_agent_cards_lob(
514516
)
515517
return []
516518

517-
# Apply optional filters
518-
if names:
519-
names_set = set(names)
520-
fragments = [f for f in fragments if f.name in names_set]
519+
# Pre-fetch filter: ORD ID is extractable from the URL without fetching the card
521520
if ord_ids:
522521
ord_ids_set = set(ord_ids)
523522
fragments = [
@@ -562,6 +561,11 @@ async def get_agent_cards_lob(
562561
"Failed to fetch agent card for fragment '%s' — skipping", fragment_name
563562
)
564563

564+
# Post-fetch filter: agent card name is only known after fetching
565+
if agent_names:
566+
agent_names_set = set(agent_names)
567+
agents = [a for a in agents if a.agent_card.raw.get("name") in agent_names_set]
568+
565569
logger.info(
566570
"Fetched %d agent card(s) from %d A2A fragment(s)", len(agents), len(fragments)
567571
)

src/sap_cloud_sdk/agentgateway/_models.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,21 +130,23 @@ class AgentCardFilter:
130130
filtering on that field).
131131
132132
Attributes:
133-
names: Fragment names to include.
134-
ord_ids: ORD IDs to include.
133+
agent_names: Agent card names to include (matched against the `name`
134+
field in the agent card JSON). Applied after fetching all cards.
135+
ord_ids: ORD IDs to include (extracted from the fragment URL).
136+
Applied before fetching, skipping non-matching fragments.
135137
136138
Example:
137139
```python
138140
from sap_cloud_sdk.agentgateway import AgentCardFilter
139141
140142
agents = await agw_client.list_agent_cards(
141143
filter=AgentCardFilter(
142-
names=["my-fragment"],
144+
agent_names=["Billing Assistant Agent"],
143145
ord_ids=["sap.s4:apiAccess:agent:v1"],
144146
)
145147
)
146148
```
147149
"""
148150

149-
names: list[str] = field(default_factory=list)
151+
agent_names: list[str] = field(default_factory=list)
150152
ord_ids: list[str] = field(default_factory=list)

src/sap_cloud_sdk/agentgateway/agw_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ async def list_agent_cards(
431431
tenant,
432432
auth.access_token,
433433
self._config.timeout,
434-
names=f.names or None,
434+
agent_names=f.agent_names or None,
435435
ord_ids=f.ord_ids or None,
436436
)
437437
except AgentGatewaySDKError:

tests/agentgateway/unit/test_agw_client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@ async def test_returns_agents_from_lob_flow(self):
877877
"my-tenant",
878878
"system-token",
879879
60.0,
880-
names=None,
880+
agent_names=None,
881881
ord_ids=None,
882882
)
883883

@@ -902,14 +902,14 @@ async def test_passes_filter_arguments(self):
902902
):
903903
agw_client = create_client(tenant_subdomain="my-tenant")
904904
await agw_client.list_agent_cards(
905-
filter=AgentCardFilter(names=["frag-1"], ord_ids=["sap.s4:agent:v1"])
905+
filter=AgentCardFilter(agent_names=["Billing Agent"], ord_ids=["sap.s4:agent:v1"])
906906
)
907907

908908
mock_lob.assert_called_once_with(
909909
"my-tenant",
910910
"token",
911911
60.0,
912-
names=["frag-1"],
912+
agent_names=["Billing Agent"],
913913
ord_ids=["sap.s4:agent:v1"],
914914
)
915915

tests/agentgateway/unit/test_lob.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -899,29 +899,33 @@ async def test_returns_empty_list_when_no_fragments(self):
899899
assert result == []
900900

901901
@pytest.mark.asyncio
902-
async def test_filters_by_names(self):
903-
"""Only include fragments whose name is in the names filter."""
902+
async def test_filters_by_agent_names(self):
903+
"""Fetch all cards then keep only those whose agent card name matches."""
904904
frag_1 = self._make_fragment("frag-1", "https://agw.example.com/v1/a2a/ord-1/t1")
905905
frag_2 = self._make_fragment("frag-2", "https://agw.example.com/v1/a2a/ord-2/t2")
906906

907+
async def _cards_by_ord(fragment_url, token, timeout):
908+
if "ord-1" in fragment_url:
909+
return AgentCard(raw={"name": "Billing Agent"})
910+
return AgentCard(raw={"name": "Other Agent"})
911+
907912
with (
908913
patch(
909914
"sap_cloud_sdk.agentgateway._lob.list_a2a_fragments",
910915
return_value=[frag_1, frag_2],
911916
),
912917
patch(
913918
"sap_cloud_sdk.agentgateway._lob._fetch_agent_card",
914-
new_callable=AsyncMock,
915-
return_value=AgentCard(raw={}),
916-
) as mock_fetch,
919+
side_effect=_cards_by_ord,
920+
),
917921
):
918922
result = await get_agent_cards_lob(
919-
"tenant-sub", "token", 60.0, names=["frag-1"]
923+
"tenant-sub", "token", 60.0, agent_names=["Billing Agent"]
920924
)
921925

922926
assert len(result) == 1
923927
assert result[0].ord_id == "ord-1"
924-
assert mock_fetch.call_count == 1
928+
assert result[0].agent_card.raw["name"] == "Billing Agent"
925929

926930
@pytest.mark.asyncio
927931
async def test_filters_by_ord_ids(self):

0 commit comments

Comments
 (0)