[Bug]: REST tenant routes are mounted before `path_prefix`, so tenant requests from the SDK client get 404
维护者通常 2 天内回复
评估
这个 Issue 还没有评估数据。
描述
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
- 主要语言
- Python
- 星标
- 2.2k
- 派生
- 518
- 平均合并
- 3 天 7 小时
- 30 天内合并 PR
- 38
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
a2aproject/a2a-python 的其他 Issue
-
[Bug]: `A2A-Version` validation ignores minor versions and the query parameter可能已有人在做 @rohityan 于 61 天前认领。 未关闭component: server status:awaiting response
难度 2/5 1-3 小时 新手友好度 75/100
a2aproject/a2a-python#1204 · 3 条评论 · 已指派 1 人 ·
维护者通常 2 天内回复
-
[Bug]: REST task/request id sanitization可能已有人在做 @Linux2010 于 120 天前认领。 未关闭maintainers-only
难度 2/5 1-3 小时 新手友好度 65/100
a2aproject/a2a-python#805 · 1 条评论 ·
维护者通常 2 天内回复
-
v0.3 REST GetTask returns 500 for a non-integer historyLength可能已有人在做 @rohityan 今天认领。 未关闭
a2aproject/a2a-python#1381 · 已指派 2 人 ·
维护者通常 2 天内回复
-
v0.3 pushNotificationConfig/get by task id fails with Validation failed可能已有人在做 @rohityan 今天认领。 未关闭
a2aproject/a2a-python#1379 · 已指派 2 人 ·
维护者通常 2 天内回复
-
[Bug]: TaskEventStream methods don't receive ServerCallContext可能已有人在做 @rohityan 于 3 天前认领。 未关闭
a2aproject/a2a-python#1374 · 已指派 2 人 ·
维护者通常 2 天内回复
查看 a2aproject/a2a-python 的全部 Issue
相似的 Issue
-
难度 1/5 1 小时以内 新手友好度 85/100
521xueweihan/HelloGitHub#4115 ·
-
get_lldp_neighbors_detail: query asks for 'max-address' (typo for 'mac-address'), so remote_chassis_id is always empty可能已有人在做 @Jah-yee 今天认领。 未关闭
难度 1/5 1 小时以内 新手友好度 88/100
-
lesson-submission pending-review
难度 1/5 1 小时以内 新手友好度 74/100
Ikalus1988/MisakaNet#3899 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100
aws-samples/sample-per-model-bedrock#549 ·
维护者通常 1 天内回复
-
难度 1/5 1 小时以内 新手友好度 90/100