From d105cc452a39ac1d0db4c702a41151989a8f5d7a Mon Sep 17 00:00:00 2001 From: Colin Harris Date: Tue, 7 Jul 2026 17:05:22 +1000 Subject: [PATCH] fix: translate :timeout to :receive_timeout in discover/2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A2A.Client.discover/2 documents a :timeout option and take_req_opts/1 keeps it, but the option was passed straight to Req.new/1, which rejects it (`unknown option :timeout`) — Req's key is :receive_timeout. Only the message-send path translated it, via merge_req_opts/2. Route discover/2's request options through merge_req_opts/2 so :timeout behaves consistently across the client API. Adds a regression test. Fixes #58 Co-Authored-By: Claude Opus 4.8 --- lib/a2a/client.ex | 9 ++++++--- test/a2a/client_test.exs | 11 +++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/a2a/client.ex b/lib/a2a/client.ex index f8243a0..d00a1d0 100644 --- a/lib/a2a/client.ex +++ b/lib/a2a/client.ex @@ -138,9 +138,12 @@ if Code.ensure_loaded?(Req) do path = Keyword.get(opts, :agent_card_path, "/.well-known/agent-card.json") req_opts = take_req_opts(opts) - base_opts = [base_url: base_url] - - req = Req.new(Keyword.merge(base_opts, req_opts)) + # Route options through merge_req_opts/2 rather than passing them + # straight to Req.new/1: it translates :timeout into Req's + # :receive_timeout (Req has no :timeout option), matching how the + # message-send functions handle it and keeping the :timeout option + # documented on discover/2 working consistently. + req = merge_req_opts(Req.new(base_url: base_url), req_opts) case Req.get(req, url: path) do {:ok, %Req.Response{status: 200, body: body}} when is_map(body) -> diff --git a/test/a2a/client_test.exs b/test/a2a/client_test.exs index 9e3ca34..bfa3a14 100644 --- a/test/a2a/client_test.exs +++ b/test/a2a/client_test.exs @@ -92,6 +92,17 @@ defmodule A2A.ClientTest do assert {:error, {:unexpected_status, 404}} = Client.discover("https://agent.example.com", plug: plug) end + + test "accepts the :timeout option without raising" do + plug = fn conn -> + json_resp(conn, 200, @agent_card_json) + end + + # :timeout must be translated to Req's :receive_timeout; passing it + # straight to Req.new/1 raises "unknown option :timeout". + assert {:ok, %AgentCard{name: "test-agent"}} = + Client.discover("https://agent.example.com", plug: plug, timeout: 60_000) + end end # -------------------------------------------------------------------