ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ZeroClaw A2A 跨实现互操作验证指南:用独立 a2a-sdk-python 服务端验证 Rust 出站客户端的 Send/Poll/Cancel 全生命周期

ZeroClaw A2A 跨实现互操作验证指南:用独立 a2a-sdk-python 服务端验证 Rust 出站客户端的 Send/Poll/Cancel 全生命周期 ZeroClaw A2A 跨实现互操作验证指南用独立 a2a-sdk-python 服务端验证 Rust 出站客户端的 Send/Poll/Cancel 全生命周期【免费下载链接】zeroclawFast, small, and fully autonomous AI personal assistant infrastructure, any OS, any platform — deploy anywhere, swap anything 项目地址: https://gitcode.com/gh_mirrors/ze/zeroclawZeroClaw 的a2a_*系列工具a2a_send/a2a_get_task/a2a_cancel/a2a_discover承担出站 A2AAgent-to-Agent协议版本 1.0调用方角色负责把任务委派给远端 A2A 兼容 Agent。本文围绕仓库内crates/zeroclaw-tools/tests/a2a_cross_harness/目录下的跨实现验证夹具cross-harness fixtures完整讲解如何用非 ZeroClaw 的独立 A2A 实现——官方a2a-sdk-python服务端栈——在本地验证客户端代码你将掌握lifecycle_server.py的启动与工作原理、两条#[ignore]交叉测试的精确运行命令以及背后的配置参数、生命周期状态机与安全边界从而把跨实现互操作性证据RFC 发布门禁复现到自己的机器上。为什么需要 Cross-Harness单测之外的互操作性证据ZeroClaw 的 A2A 出站客户端crates/zeroclaw-tools/src/a2a_client.rs实现的是 A2A 协议调用方caller角色它把任务通过 JSON-RPCmessage/send委派给远端 Agent再通过GetTask轮询、CancelTask取消。仓库内常规的单测使用 mock 服务器模拟对端例如 a2a_client.rs 用 mock 验证max_response_bytes上限但 mock 无法证明一个关键事实我们写出的 wire 报文能被真正独立实现的 A2A 服务端正确理解。这正是 cross-harness 夹具存在的意义。tests/a2a_cross_harness/README.md 明确指出这些夹具用于对照独立的 A2A 实现——官方a2a-sdk-python服务端栈既不是 ZeroClaw 自身也不是我们客户端的 mock——手动验证出站a2a_*客户端。这是 RFC 发布门禁rollout gate要求的互操作性证据。与任何外部集成测试一样它不会在单元 CI 中运行因为 CI 没有预置可用的 A2A 对端#[ignore]属性将其排除在单元 CI 之外必须按本文步骤在本地运行。认识 lifecycle_server.py支持取消的独立 A2A 服务端lifecycle_server.py 是一个基于官方a2a-sdk-python构建的小型 A2A 服务端其核心设计目标是补上官方helloworld示例无法覆盖的场景取消路径。官方 helloworld 样例在收到cancel时会抛出NotImplementedError而lifecycle_server.py中的 Agent 任务会进入非终止态WORKING永远不会自行完成——客户端可以用GetTask轮询它并用CancelTask将其终止到CANCELED。从源码看它由以下几部分组成LifecycleAgentExecutor(AgentExecutor)lifecycle_server.pyexecute先把任务入队event_queue.enqueue_event再用TaskUpdater.update_status将其标记为TASK_STATE_WORKING非终止、可轮询随后asyncio.sleep(3600)模拟永不自行结束的长任务cancel则通过TaskUpdater.update_status把状态更新为TASK_STATE_CANCELED使后续GetTask能观察到终止态。build_server()lifecycle_server.py声明一个AgentCard技能Lifecycle、JSONRPC协议绑定、protocol_version1.0、RPC URL 指向http://127.0.0.1:43100并挂载两个路由集合——create_agent_card_routes(card)提供/.well-known/agent-card.json发现端点与create_jsonrpc_routes(handler, /)提供 JSON-RPC 调用端点。入口lifecycle_server.pyuvicorn.run(build_server(), host127.0.0.1, port43100)。安装与启动服务端依赖 Python 的a2a-sdk包安装命令pip install a2a-sdk uvicorn启动python3 lifecycle_server.py # listens on http://127.0.0.1:43100运行客户端的 Cross-Harness 测试在服务端运行期间从仓库根目录执行以下步骤。首先确认独立对端已经就绪# Verify the independent peer is up curl http://127.0.0.1:43100/.well-known/agent-card.json然后运行生命周期send → poll → cancel交叉测试——这是本 PR 作为取消门禁cancellation gate使用的测试cargo test -p zeroclaw-tools a2a_client::tests::cross_harness_send_poll_cancel_independent_peer -- --ignored第二条测试覆盖 send → poll → 终止流程针对的是另一个独立对端——官方 helloworld 示例a2a-sdk-python服务端默认端口 9999# cd a2aproject/a2a-samples/samples/python/agents/helloworld python3 __main__.py cargo test -p zeroclaw-tools a2a_client::tests::cross_harness_send_and_poll_official_peer -- --ignored#[ignore]属性保证这些测试不会进入单元 CICI 中没有 A2A 对端但它们正是跨实现互操作性的可复现证据。两条交叉测试的源码视角两条测试都定义在 a2a_client.rs 的tests模块中共享同一个测试配置构造器cross_harness_configa2a_client.rs该配置打开a2a.client.enabled、allow_private_hosts true本地对端在127.0.0.1、card_cache_ttl_secs 0每次都拉取最新 Agent Card并注册名为google-helloworld的 peer。cross_harness_send_and_poll_official_peera2a_client.rs通过环境变量A2A_CROSS_HARNESS_URL指定对端地址默认http://127.0.0.1:9999。测试步骤是 ①a2a_discover拉取并断言对端卡片名包含 Hello World②a2a_send携带return_immediately: true期望得到非终止任务并断言路由缓存已写入③ 循环a2a_get_task轮询最多 20 次、间隔 200ms直到状态进入COMPLETED/FAILED/CANCELED最终断言为TASK_STATE_COMPLETED——完整覆盖非终止 → 轮询 → 终止的异步生命周期。cross_harness_send_poll_cancel_independent_peera2a_client.rs通过A2A_CROSS_HARNESS_CANCEL_URL指定地址默认http://127.0.0.1:43100。它先 discover 独立对端的卡片再a2a_sendreturn_immediately: true让任务进入可轮询的非终止态SUBMITTED/WORKING随后a2a_cancel并断言任务状态包含CANCELED——这正是此前从未验证过的取消门禁。理解被测对象a2a_* 工具与客户端生命周期四个工具的角色四个工具的name()定义如下源码位置见 a2a_client.rs工具名对应类职责a2a_discoverA2aDiscoverTool读取操作ToolOperation::Read拉取对端 Agent Card可按filter_tags过滤a2a_sendA2aSendTool调用SendMessage协议 §9.4.1委派任务return_immediately: true时返回非终止任务供后续轮询a2a_get_taskA2aGetTaskTool调用GetTask轮询任务直至终止态a2a_cancelA2aCancelTool调用CancelTask把在途任务取消到CANCELED客户端关键实现机制A2aHttpClienta2a_client.rs持有多项支撑跨任务生命周期连续性的机制理解它们有助于读懂交叉测试为什么能跑通路由缓存route cacheSendMessage会把选中的对端/Agent/RPC URL/tenant 以(peer, agent, task_id)为键写入进程级共享缓存shared_a2a_route_cachea2a_client.rs。后续GetTask/CancelTask即使发生在另一次process_message回合、面对全新的A2aHttpClient实例会复用同一个端点避免把轮询/取消发到与创建任务时不同的接口上。缓存有界上限 1024 条单条保留字符串上限 4096 字节见 a2a_client.rs条目在任务进入终止态后被清除守护进程重启自然清空。Agent Card 缓存按 peer 的base_url键控card_cache_ttl_secs 0时禁用缓存协议要求过期条目自动重新拉取base_url变化即换键天然失效旧缓存。SendMessageResponse联合解析对端可能直接返回Message回复此时折叠成合成Task任务 ID 沿用对端messageId见 a2a_client.rs也可能返回真正的Task交叉测试通过return_immediately: true强制走任务分支从而验证非终止状态的真实流转。传输选择协议 §5.2select_interfacea2a_client.rs从对端卡片的supportedInterfaces中筛选protocolVersion 1.0的 JSON-RPC 接口单接口卡片直接选中多接口聚合卡片则按/a2a/{agent}URL 后缀或tenant解析路由身份无法唯一确定时失败关闭绝不静默路由到错误接口无卡片对端回退到惯例路径base/a2a/{agent}。安全边界为什么本地对端需要放行出站 A2A 是一个 SSRF 面。客户端复用http_request的helpers::domain_guard策略a2a_client.rs对端 URL 的 host 字面量与 DNS 解析结果都会接受私网/回环/链路本地/云元数据地址检查云元数据地址如 IMDS无条件拦截私网 host 默认拒绝。由于交叉测试的对端跑在127.0.0.1测试配置必须显式打开allow_private_hosts truea2a_client.rs才会被放行。此外客户端不跟随重定向、拒绝 URL 中的 userinfo并通过 DNS pinresolve_to_addrs封堵 DNS rebinding 缺口当运行时代理对 a2a 服务生效时直接失败关闭因为代理侧会自行解析目标主机名、本地 pin 无法保证目的地安全。配置文件全景把这些参数写进真实部署交叉测试以代码方式构造配置真实部署则在zeroclaw.toml中声明相同的参数。对应的配置结构定义在 crates/zeroclaw-config/src/multi_agent.rsA2aClientConfig与 multi_agent.rsA2aClientPeerConfig[a2a.client] enabled true request_timeout_secs 120 # 单次 JSON-RPC 调用超时默认 120s0 会回退到安全默认 30s card_cache_ttl_secs 300 # Agent Card 缓存 TTL默认 300s0 每次重新拉取 allow_private_hosts true # 默认 false本地/内网对端需设为 true allowed_private_hosts [] # 精确允许的私网 host支持 *.suffix 通配 max_response_bytes 1000000 # 响应体上限默认 1MB0 不限制不推荐 [[a2a.client.peers]] name google-helloworld # 工具调用中的 peer 参数全局唯一不能为空或重复 base_url http://127.0.0.1:43100 token # Bearer token${VAR} 从环境变量解析空值不发送 Authorization 头参数要点均以源码为准enabled默认false未配置的安装不注册任何a2a_*工具、不尝试连接任何对端默认关闭最小攻击面。request_timeout_secs默认120注意客户端构造逻辑a2a_client.rs把0视为危险默认值回退到 30s 安全超时。peername必须全局唯一客户端在构造时validate_peer_names_uniquea2a_client.rs及每次resolve_peer时都会校验空名/重名并失败关闭避免目的地与凭据映射歧义。token支持两层解析resolve_peer_tokena2a_client.rs先经SecretStore解密若为加密密文再对结果做${VAR}环境变量插值变量名只允许 ASCII 字母、数字、下划线缺失或空值直接报错。该字段被标记为#[secret]在配置/UI 面按写保护处理。总结与排查要点跨实现互操作验证的核心链路可以概括为a2a_send(return_immediatelytrue)让独立对端返回非终止任务 →a2a_get_task轮询 → 终止态结束官方 helloworld 对端或a2a_cancel取消到CANCELEDlifecycle_server 对端。本地复现时如遇问题优先按以下顺序排查对端是否就绪curl http://127.0.0.1:43100/.well-known/agent-card.json必须返回合法 Agent Cardpip install a2a-sdk uvicorn是否完成。端口与 URL 覆盖取消测试默认http://127.0.0.1:43100轮询测试默认http://127.0.0.1:9999分别可用A2A_CROSS_HARNESS_CANCEL_URL与A2A_CROSS_HARNESS_URL环境变量覆盖。私网放行本地对端必须打开allow_private_hosts或把127.0.0.1加入allowed_private_hosts否则guard_host会以private/loopback 不允许拒绝请求。代理干扰若运行时代理对 a2a 服务生效客户端会失败关闭本地验证时确认无代理命中tool.a2a。测试标记两条交叉测试都带#[ignore]运行时必须追加-- --ignored否则 cargo 会直接跳过。理解这些步骤之后你既可以在本地把 ZeroClaw 的 A2A 出站客户端与官方 Python 实现对接起来完成互操作门禁验证也掌握了把这些参数迁移到真实[a2a.client]配置、接入任意 A2A 兼容对端的完整方法。【免费下载链接】zeroclawFast, small, and fully autonomous AI personal assistant infrastructure, any OS, any platform — deploy anywhere, swap anything 项目地址: https://gitcode.com/gh_mirrors/ze/zeroclaw创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表