Skip to content

Commit 9e51254

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

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
@@ -809,6 +809,36 @@ def build(self) -> list[Route]:
809809
return routes
810810

811811

812+
def _join_url(base: str, *paths: str) -> str:
813+
"""Joins a base URL with one or more URL path fragments into a normalized absolute URL.
814+
815+
This method ensures that redundant slashes are removed between path segments,
816+
and that the resulting URL is correctly formatted.
817+
818+
Args:
819+
base: The base URL.
820+
*paths: One or more URL fragments to append to the base path.
821+
822+
Returns:
823+
A well-formed absolute URL with the joined path components.
824+
"""
825+
parsed = urlparse(base)
826+
clean_paths = [p.strip('/') for p in paths]
827+
joined_path = posixpath.join(parsed.path.rstrip('/'), *clean_paths)
828+
return urlunparse(parsed._replace(path='/' + joined_path))
829+
830+
def _get_path_from_url(url: str) -> str:
831+
"""Extracts and returns the path component from a full URL.
832+
833+
Args:
834+
url: The full URL string.
835+
836+
Returns:
837+
The path component of the URL.
838+
"""
839+
path = urlparse(url).path
840+
return path if path else '/'
841+
812842
class A2AStarletteBuilder:
813843
"""Builder class for assembling a Starlette application with A2A protocol routes.
814844
@@ -833,25 +863,6 @@ def __init__(self):
833863
self._mounts: list[Mount] = []
834864
self._catalog_links: list[AgentLinkContext] = []
835865

836-
@staticmethod
837-
def _join_url(base: str, *paths: str) -> str:
838-
"""Joins a base URL with one or more URL path fragments into a normalized absolute URL.
839-
840-
This method ensures that redundant slashes are removed between path segments,
841-
and that the resulting URL is correctly formatted.
842-
843-
Args:
844-
base: The base URL.
845-
*paths: One or more URL fragments to append to the base path.
846-
847-
Returns:
848-
A well-formed absolute URL with the joined path components.
849-
"""
850-
parsed = urlparse(base)
851-
clean_paths = [p.strip('/') for p in paths]
852-
joined_path = posixpath.join(parsed.path.rstrip('/'), *clean_paths)
853-
return urlunparse(parsed._replace(path='/' + joined_path))
854-
855866
async def _handle_get_api_catalog(self, request: Request) -> JSONResponse:
856867
"""Handles GET requests for the AgentCatalog endpoint.
857868
@@ -866,14 +877,14 @@ async def _handle_get_api_catalog(self, request: Request) -> JSONResponse:
866877

867878
def mount(
868879
self,
869-
path: str,
870880
route_builder: A2AStarletteRouteBuilder,
871881
) -> Self:
872882
"""Mounts routes generated by the given builder and adds metadata to the agent catalog.
873883
874884
Raises:
875885
ValueError: If a mount for the given path already exists.
876886
"""
887+
path = _get_path_from_url(route_builder.agent_card.url)
877888
if any(
878889
posixpath.normpath(mount.path) == posixpath.normpath(path)
879890
for mount in self._mounts

0 commit comments

Comments
 (0)