[Bug]: REST tenant routes are mounted before `path_prefix`, so tenant requests from the SDK client get 404
Los mantenedores suelen responder en 2 días
Evaluación
Este issue todavía no se ha evaluado.
Descripción
What happened?
With a non-empty path_prefix, create_rest_routes serves the tenant routes in front of the prefix, at /{tenant}{path_prefix}/.... The SDK's own REST client sends the tenant after the prefix, at {path_prefix}/{tenant}/..., so a client whose AgentInterface sets tenant gets a 404 on every call.
In src/a2a/server/routes/rest_routes.py, the tenant routes come from Mount(path='/{tenant}', routes=base_route_objects), and base_route_objects already include path_prefix. On the client side, RestTransport._get_path returns /{tenant}{base_path}, which is appended to the interface URL. The HTTP bindings in a2a.proto also put the tenant right after the interface URL (post: "/{tenant}/message:send"). The hello_world_agent sample serves REST with path_prefix='/a2a/rest' and advertises an interface URL ending in /a2a/rest, so the prefix is meant to be part of the interface URL.
This changed in #892. Before it, the REST adapter built /{tenant}{path} and the FastAPI app added rpc_url in front, so the prefix came first. Without a prefix both layouts are the same, so only servers that set path_prefix are affected.
To reproduce, pip install "a2a-sdk[http-server]==1.2.3" and run:
import asyncio
from unittest.mock import AsyncMock
import httpx
from starlette.applications import Starlette
from a2a.client import ClientConfig, ClientFactory
from a2a.server.request_handlers import RequestHandler
from a2a.server.routes import create_rest_routes
from a2a.types import AgentCard, AgentInterface, ListTasksRequest, ListTasksResponse
handler = AsyncMock(spec=RequestHandler)
handler.on_list_tasks.return_value = ListTasksResponse()
app = Starlette(routes=create_rest_routes(handler, path_prefix="/a2a/rest"))
card = AgentCard(supported_interfaces=[AgentInterface(
url="http://test/a2a/rest", protocol_binding="HTTP+JSON",
protocol_version="1.0", tenant="acme")])
async def main():
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://test") as http:
for path in ("/a2a/rest/acme/tasks", "/acme/a2a/rest/tasks"):
r = await http.get(path, headers={"A2A-Version": "1.0"})
print(path, r.status_code)
client = ClientFactory(ClientConfig(httpx_client=http, supported_protocol_bindings=["HTTP+JSON"])).create(card)
try:
await client.list_tasks(ListTasksRequest())
print("list_tasks: ok")
except Exception as e:
print(f"list_tasks: {type(e).__name__}: {e}")
asyncio.run(main())
I expected /a2a/rest/acme/tasks to return 200 and list_tasks to succeed.
I have a fix with a test and will open a PR.
Relevant log output
/a2a/rest/acme/tasks 404
/acme/a2a/rest/tasks 200
list_tasks: MethodNotFoundError: Resource not found: http://test/a2a/rest/acme/tasks
Code of Conduct
- I agree to follow this project's Code of Conduct
- Lenguaje dominante
- Python
- Estrellas
- 2.2k
- Forks
- 518
- Merge medio
- 3 d 7 h
- PR fusionados (30 d)
- 38
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de a2aproject/a2a-python
-
[Bug]: `A2A-Version` validation ignores minor versions and the query parameterPosiblemente ocupada @rohityan la tomó hace 62 días. Abiertocomponent: server status:awaiting response
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
a2aproject/a2a-python#1204 · 3 comentarios · 1 asignado ·
Los mantenedores suelen responder en 2 días
-
[Bug]: REST task/request id sanitizationPosiblemente ocupada @Linux2010 la tomó hace 120 días. Abiertomaintainers-only
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
a2aproject/a2a-python#805 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
v0.3 REST GetTask returns 500 for a non-integer historyLengthPosiblemente ocupada @rohityan la tomó hoy. Abierto
a2aproject/a2a-python#1381 · 2 asignados ·
Los mantenedores suelen responder en 2 días
-
v0.3 pushNotificationConfig/get by task id fails with Validation failedPosiblemente ocupada @rohityan la tomó hoy. Abierto
a2aproject/a2a-python#1379 · 2 asignados ·
Los mantenedores suelen responder en 2 días
-
[Bug]: TaskEventStream methods don't receive ServerCallContextPosiblemente ocupada @rohityan la tomó hace 3 días. Abierto
a2aproject/a2a-python#1374 · 2 asignados ·
Los mantenedores suelen responder en 2 días
Todos los issues de a2aproject/a2a-python
Issues similares
-
Link Checker ReportAbiertoautomated issue linkchecker report
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
QuantEcon/lecture-python.myst#1098 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
-
[Bug]: Processing errors missing from Docker logs due to incorrect console-handler detectionAbiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
podly-pure-podcasts/podly_pure_podcasts#279 ·
Los mantenedores suelen responder en 1 día
-
New template proposal: ljpAbiertotemplate-proposal
Dificultad 1/5 Menos de una hora Aptitud para principiantes 78/100
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 82/100
OpenShot/openshot-qt#6230 ·
Los mantenedores suelen responder en 1 día