Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

[Bug]: REST tenant routes are mounted before `path_prefix`, so tenant requests from the SDK client get 404

未关闭
#1,376 0 条评论 0 个 reaction 已指派 2 人 在 GitHub 查看

维护者通常 2 天内回复

@rohityan 已经在做这个了。

开始于 2026年10月25日。

  • #1377 来自 @Revinand —— 未关闭

评估

这个 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

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

a2aproject/a2a-python 的其他 Issue

查看 a2aproject/a2a-python 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。