Skip to content

Commit 46f33b2

Browse files
committed
fix: ensure correct agent URL path parsing and registration in Starlette app
Signed-off-by: Shingo OKAWA <[email protected]>
1 parent d15b197 commit 46f33b2

File tree

3 files changed

+42
-22
lines changed

3 files changed

+42
-22
lines changed

pyproject.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ exclude = [
6262
vcs = "git"
6363
style = "pep440"
6464

65+
[tool.uv.workspace]
66+
members = [
67+
"examples/apicatalog",
68+
]
69+
6570
[dependency-groups]
6671
dev = [
6772
"datamodel-code-generator>=0.30.0",

src/a2a/server/apps/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
"""HTTP application components for the A2A server."""
22

3-
from a2a.server.apps.starlette_app import A2AStarletteApplication
3+
from a2a.server.apps.starlette_app import A2AStarletteApplication, A2AStarletteRouteBuilder, A2AStarletteBuilder
44

55

6-
__all__ = ['A2AStarletteApplication']
6+
__all__ = [
7+
'A2AStarletteApplication',
8+
'A2AStarletteRouteBuilder',
9+
'A2AStarletteBuilder',
10+
]

src/a2a/server/apps/starlette_app.py

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,36 @@ def build(self) -> list[Route]:
821821
return routes
822822

823823

824+
def _join_url(base: str, *paths: str) -> str:
825+
"""Joins a base URL with one or more URL path fragments into a normalized absolute URL.
826+
827+
This method ensures that redundant slashes are removed between path segments,
828+
and that the resulting URL is correctly formatted.
829+
830+
Args:
831+
base: The base URL.
832+
*paths: One or more URL fragments to append to the base path.
833+
834+
Returns:
835+
A well-formed absolute URL with the joined path components.
836+
"""
837+
parsed = urlparse(base)
838+
clean_paths = [p.strip('/') for p in paths]
839+
joined_path = posixpath.join(parsed.path.rstrip('/'), *clean_paths)
840+
return urlunparse(parsed._replace(path='/' + joined_path))
841+
842+
def _get_path_from_url(url: str) -> str:
843+
"""Extracts and returns the path component from a full URL.
844+
845+
Args:
846+
url: The full URL string.
847+
848+
Returns:
849+
The path component of the URL.
850+
"""
851+
path = urlparse(url).path
852+
return path if path else '/'
853+
824854
class A2AStarletteBuilder:
825855
"""Builder class for assembling a Starlette application with A2A protocol routes.
826856
@@ -845,25 +875,6 @@ def __init__(self):
845875
self._mounts: list[Mount] = []
846876
self._catalog_links: list[AgentLinkContext] = []
847877

848-
@staticmethod
849-
def _join_url(base: str, *paths: str) -> str:
850-
"""Joins a base URL with one or more URL path fragments into a normalized absolute URL.
851-
852-
This method ensures that redundant slashes are removed between path segments,
853-
and that the resulting URL is correctly formatted.
854-
855-
Args:
856-
base: The base URL.
857-
*paths: One or more URL fragments to append to the base path.
858-
859-
Returns:
860-
A well-formed absolute URL with the joined path components.
861-
"""
862-
parsed = urlparse(base)
863-
clean_paths = [p.strip('/') for p in paths]
864-
joined_path = posixpath.join(parsed.path.rstrip('/'), *clean_paths)
865-
return urlunparse(parsed._replace(path='/' + joined_path))
866-
867878
async def _handle_get_api_catalog(self, request: Request) -> JSONResponse:
868879
"""Handles GET requests for the AgentCatalog endpoint.
869880
@@ -878,14 +889,14 @@ async def _handle_get_api_catalog(self, request: Request) -> JSONResponse:
878889

879890
def mount(
880891
self,
881-
path: str,
882892
route_builder: A2AStarletteRouteBuilder,
883893
) -> Self:
884894
"""Mounts routes generated by the given builder and adds metadata to the agent catalog.
885895
886896
Raises:
887897
ValueError: If a mount for the given path already exists.
888898
"""
899+
path = _get_path_from_url(route_builder.agent_card.url)
889900
if any(
890901
posixpath.normpath(mount.path) == posixpath.normpath(path)
891902
for mount in self._mounts

0 commit comments

Comments
 (0)