From 3d7503ce826e28d5927eb79745d29a5ec5915334 Mon Sep 17 00:00:00 2001 From: "Panek, Tomasz" Date: Fri, 17 Oct 2025 18:37:59 +0200 Subject: [PATCH 01/10] moving java classes to maven based convention folder --- .../java/com/example/a2a_basic/A2AAgent.java | 85 +++++++++++++++++ .../com/example/a2a_basic/A2AAgentRun.java | 93 +++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgent.java create mode 100644 contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgentRun.java diff --git a/contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgent.java b/contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgent.java new file mode 100644 index 000000000..1c684e188 --- /dev/null +++ b/contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgent.java @@ -0,0 +1,85 @@ +package com.example.a2a_basic; + +import com.google.adk.a2a.A2AClient; +import com.google.adk.a2a.RemoteA2AAgent; +import com.google.adk.agents.BaseAgent; +import com.google.adk.agents.LlmAgent; +import com.google.adk.tools.FunctionTool; +import com.google.adk.tools.ToolContext; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import io.a2a.client.http.JdkA2AHttpClient; +import io.a2a.spec.AgentCapabilities; +import io.a2a.spec.AgentCard; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** Provides local roll logic plus a remote A2A agent for the demo. */ +public final class A2AAgent { + + private static final Random RANDOM = new Random(); + + @SuppressWarnings("unchecked") + public static ImmutableMap rollDie(int sides, ToolContext toolContext) { + ArrayList rolls = + (ArrayList) toolContext.state().computeIfAbsent("rolls", k -> new ArrayList<>()); + int result = RANDOM.nextInt(Math.max(sides, 1)) + 1; + rolls.add(result); + return ImmutableMap.of("result", result); + } + + public static final LlmAgent ROLL_AGENT = + LlmAgent.builder() + .name("roll_agent") + .model("gemini-2.0-flash") + .description("Handles rolling dice of different sizes.") + .instruction( + """ + When asked to roll a die, always call the roll_die tool with the requested number of + sides (default to 6 if unspecified). Do not fabricate results. + """) + .tools(ImmutableList.of(FunctionTool.create(A2AAgent.class, "rollDie"))) + .build(); + + public static LlmAgent createRootAgent(String primeAgentBaseUrl) { + BaseAgent primeAgent = createRemoteAgent(primeAgentBaseUrl); + return LlmAgent.builder() + .name("root_agent") + .model("gemini-2.0-flash") + .instruction( + """ + You can roll dice locally and delegate prime-checking to the remote prime_agent. + 1. When the user asks to roll a die, route the request to roll_agent. + 2. When the user asks to check primes, delegate to prime_agent. + 3. If the user asks to roll and then check, roll_agent first, then prime_agent with the result. + Always recap the die result before discussing primality. + """) + .subAgents(ImmutableList.of(ROLL_AGENT, primeAgent)) + .build(); + } + + private static BaseAgent createRemoteAgent(String primeAgentBaseUrl) { + AgentCapabilities capabilities = new AgentCapabilities.Builder().build(); + AgentCard agentCard = + new AgentCard.Builder() + .name("prime_agent") + .description("Stub agent metadata used for third-party A2A demo") + .url(primeAgentBaseUrl) + .version("1.0.0") + .capabilities(capabilities) + .defaultInputModes(List.of("text")) + .defaultOutputModes(List.of("text")) + .skills(List.of()) + .security(List.of()) + .build(); + A2AClient client = new A2AClient(agentCard, new JdkA2AHttpClient(), /* defaultHeaders= */ null); + return RemoteA2AAgent.builder() + .name(agentCard.name()) + .agentCardOrSource(agentCard) + .a2aClient(client) + .build(); + } + + private A2AAgent() {} +} diff --git a/contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgentRun.java b/contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgentRun.java new file mode 100644 index 000000000..406a8dcbc --- /dev/null +++ b/contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgentRun.java @@ -0,0 +1,93 @@ +package com.example.a2a_basic; + +import com.google.adk.agents.BaseAgent; +import com.google.adk.agents.LlmAgent; +import com.google.adk.agents.RunConfig; +import com.google.adk.artifacts.InMemoryArtifactService; +import com.google.adk.events.Event; +import com.google.adk.runner.Runner; +import com.google.adk.sessions.InMemorySessionService; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.genai.types.Content; +import com.google.genai.types.Part; +import io.reactivex.rxjava3.core.Flowable; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** Main class to demonstrate running the A2A agent with sequential inputs. */ +public final class A2AAgentRun { + private final String userId; + private final String sessionId; + private final Runner runner; + + public A2AAgentRun(BaseAgent agent) { + this.userId = "test_user"; + String appName = "A2AAgentApp"; + this.sessionId = UUID.randomUUID().toString(); + + InMemoryArtifactService artifactService = new InMemoryArtifactService(); + InMemorySessionService sessionService = new InMemorySessionService(); + this.runner = + new Runner(agent, appName, artifactService, sessionService, /* memoryService= */ null); + + ConcurrentMap initialState = new ConcurrentHashMap<>(); + var unused = + sessionService.createSession(appName, userId, initialState, sessionId).blockingGet(); + } + + private List run(String prompt) { + System.out.println("\n--------------------------------------------------"); + System.out.println("You> " + prompt); + Content userMessage = + Content.builder() + .role("user") + .parts(ImmutableList.of(Part.builder().text(prompt).build())) + .build(); + return processRunRequest(userMessage); + } + + private List processRunRequest(Content inputContent) { + RunConfig runConfig = RunConfig.builder().build(); + Flowable eventStream = + this.runner.runAsync(this.userId, this.sessionId, inputContent, runConfig); + List agentEvents = Lists.newArrayList(eventStream.blockingIterable()); + System.out.println("Agent>"); + for (Event event : agentEvents) { + if (event.content().isPresent() && event.content().get().parts().isPresent()) { + event + .content() + .get() + .parts() + .get() + .forEach( + part -> { + if (part.text().isPresent()) { + System.out.println(" Text: " + part.text().get().stripTrailing()); + } + }); + } + if (event.actions() != null && event.actions().transferToAgent().isPresent()) { + System.out.println(" Actions: transferTo=" + event.actions().transferToAgent().get()); + } + System.out.println(" Raw Event: " + event); + } + return agentEvents; + } + + public static void main(String[] args) { + String primeAgentUrl = args.length > 0 ? args[0] : "http://localhost:9876/a2a/prime_agent"; + LlmAgent agent = A2AAgent.createRootAgent(primeAgentUrl); + A2AAgentRun a2aRun = new A2AAgentRun(agent); + + // First user input + System.out.println("Running turn 1"); + a2aRun.run("Roll a dice of 6 sides."); + + // Follow-up input triggers the remote prime agent so the A2A request is logged. + System.out.println("Running turn 2"); + a2aRun.run("Is this number a prime number?"); + } +} From 0daef2a589c01c31e6051c5204a8d4a1e65ec63d Mon Sep 17 00:00:00 2001 From: "Panek, Tomasz" Date: Fri, 17 Oct 2025 19:28:39 +0200 Subject: [PATCH 02/10] moving java classes to maven based convention folder --- .../a2a_remote/remote_prime_agent/Agent.java | 101 ++++++++++++++++++ .../a2a_remote/remote_prime_agent/agent.json | 17 +++ 2 files changed, 118 insertions(+) create mode 100644 contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/remote_prime_agent/Agent.java create mode 100644 contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/remote_prime_agent/agent.json diff --git a/contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/remote_prime_agent/Agent.java b/contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/remote_prime_agent/Agent.java new file mode 100644 index 000000000..a0072e8e3 --- /dev/null +++ b/contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/remote_prime_agent/Agent.java @@ -0,0 +1,101 @@ +package com.google.adk.samples.a2a_remote.remote_prime_agent; + +import static java.util.stream.Collectors.joining; + +import com.google.adk.agents.LlmAgent; +import com.google.adk.tools.FunctionTool; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.flogger.GoogleLogger; +import io.reactivex.rxjava3.core.Maybe; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** Agent that can check whether numbers are prime. */ +public final class Agent { + + private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); + + public static ImmutableMap checkPrime(List nums) { + logger.atInfo().log("checkPrime called with nums=%s", nums); + Set primes = new HashSet<>(); + for (int num : nums) { + if (num <= 1) { + continue; + } + boolean isPrime = true; + for (int i = 2; i <= Math.sqrt(num); i++) { + if (num % i == 0) { + isPrime = false; + break; + } + } + if (isPrime) { + primes.add(num); + } + } + String result; + if (primes.isEmpty()) { + result = "No prime numbers found."; + } else if (primes.size() == 1) { + int only = primes.iterator().next(); + // Per request: singular phrasing without article + result = only + " is prime number."; + } else { + result = primes.stream().map(String::valueOf).collect(joining(", ")) + " are prime numbers."; + } + logger.atInfo().log("checkPrime result=%s", result); + return ImmutableMap.of("result", result); + } + + public static final LlmAgent ROOT_AGENT = + LlmAgent.builder() + .model("gemini-2.5-pro") + .name("check_prime_agent") + .description("check prime agent that can check whether numbers are prime.") + .instruction( + """ + You check whether numbers are prime. + + If the last user message contains numbers, call checkPrime exactly once with exactly + those integers as a list (e.g., [2]). Never add other numbers. Do not ask for + clarification. Return only the tool's result. + + Always pass a list of integers to the tool (use a single-element list for one + number). Never pass strings. + """) + // Log the exact contents passed to the LLM request for verification + .beforeModelCallback( + (callbackContext, llmRequest) -> { + try { + logger.atInfo().log( + "Invocation events (count=%d): %s", + callbackContext.events().size(), callbackContext.events()); + } catch (Throwable t) { + logger.atWarning().withCause(t).log("BeforeModel logging error"); + } + return Maybe.empty(); + }) + .afterModelCallback( + (callbackContext, llmResponse) -> { + try { + String content = + llmResponse.content().map(Object::toString).orElse(""); + logger.atInfo().log("AfterModel content=%s", content); + llmResponse + .errorMessage() + .ifPresent( + error -> + logger.atInfo().log( + "AfterModel errorMessage=%s", error.replace("\n", "\\n"))); + } catch (Throwable t) { + logger.atWarning().withCause(t).log("AfterModel logging error"); + } + return Maybe.empty(); + }) + .tools(ImmutableList.of(FunctionTool.create(Agent.class, "checkPrime"))) + .build(); + + private Agent() {} +} diff --git a/contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/remote_prime_agent/agent.json b/contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/remote_prime_agent/agent.json new file mode 100644 index 000000000..87f2d9ecc --- /dev/null +++ b/contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/remote_prime_agent/agent.json @@ -0,0 +1,17 @@ +{ + "capabilities": {}, + "defaultInputModes": ["text/plain"], + "defaultOutputModes": ["application/json"], + "description": "An agent specialized in checking whether numbers are prime. It can efficiently determine the primality of individual numbers or lists of numbers.", + "name": "check_prime_agent", + "skills": [ + { + "id": "prime_checking", + "name": "Prime Number Checking", + "description": "Check if numbers in a list are prime using efficient mathematical algorithms", + "tags": ["mathematical", "computation", "prime", "numbers"] + } + ], + "url": "http://localhost:8080/a2a/prime_agent", + "version": "1.0.0" +} From 87ee5a0fd66ea85c2d1b99e3f690112736a6c9c5 Mon Sep 17 00:00:00 2001 From: "Panek, Tomasz" Date: Fri, 17 Oct 2025 19:29:15 +0200 Subject: [PATCH 03/10] moving java classes to maven based convention folder --- contrib/samples/a2a_basic/A2AAgent.java | 85 --------------- contrib/samples/a2a_basic/A2AAgentRun.java | 93 ---------------- contrib/samples/a2a_basic/pom.xml | 20 +--- contrib/samples/a2a_remote/pom.xml | 19 ---- .../a2a_remote/remote_prime_agent/Agent.java | 101 ------------------ .../a2a_remote/remote_prime_agent/agent.json | 17 --- 6 files changed, 1 insertion(+), 334 deletions(-) delete mode 100644 contrib/samples/a2a_basic/A2AAgent.java delete mode 100644 contrib/samples/a2a_basic/A2AAgentRun.java delete mode 100644 contrib/samples/a2a_remote/remote_prime_agent/Agent.java delete mode 100644 contrib/samples/a2a_remote/remote_prime_agent/agent.json diff --git a/contrib/samples/a2a_basic/A2AAgent.java b/contrib/samples/a2a_basic/A2AAgent.java deleted file mode 100644 index 1c684e188..000000000 --- a/contrib/samples/a2a_basic/A2AAgent.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.example.a2a_basic; - -import com.google.adk.a2a.A2AClient; -import com.google.adk.a2a.RemoteA2AAgent; -import com.google.adk.agents.BaseAgent; -import com.google.adk.agents.LlmAgent; -import com.google.adk.tools.FunctionTool; -import com.google.adk.tools.ToolContext; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import io.a2a.client.http.JdkA2AHttpClient; -import io.a2a.spec.AgentCapabilities; -import io.a2a.spec.AgentCard; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -/** Provides local roll logic plus a remote A2A agent for the demo. */ -public final class A2AAgent { - - private static final Random RANDOM = new Random(); - - @SuppressWarnings("unchecked") - public static ImmutableMap rollDie(int sides, ToolContext toolContext) { - ArrayList rolls = - (ArrayList) toolContext.state().computeIfAbsent("rolls", k -> new ArrayList<>()); - int result = RANDOM.nextInt(Math.max(sides, 1)) + 1; - rolls.add(result); - return ImmutableMap.of("result", result); - } - - public static final LlmAgent ROLL_AGENT = - LlmAgent.builder() - .name("roll_agent") - .model("gemini-2.0-flash") - .description("Handles rolling dice of different sizes.") - .instruction( - """ - When asked to roll a die, always call the roll_die tool with the requested number of - sides (default to 6 if unspecified). Do not fabricate results. - """) - .tools(ImmutableList.of(FunctionTool.create(A2AAgent.class, "rollDie"))) - .build(); - - public static LlmAgent createRootAgent(String primeAgentBaseUrl) { - BaseAgent primeAgent = createRemoteAgent(primeAgentBaseUrl); - return LlmAgent.builder() - .name("root_agent") - .model("gemini-2.0-flash") - .instruction( - """ - You can roll dice locally and delegate prime-checking to the remote prime_agent. - 1. When the user asks to roll a die, route the request to roll_agent. - 2. When the user asks to check primes, delegate to prime_agent. - 3. If the user asks to roll and then check, roll_agent first, then prime_agent with the result. - Always recap the die result before discussing primality. - """) - .subAgents(ImmutableList.of(ROLL_AGENT, primeAgent)) - .build(); - } - - private static BaseAgent createRemoteAgent(String primeAgentBaseUrl) { - AgentCapabilities capabilities = new AgentCapabilities.Builder().build(); - AgentCard agentCard = - new AgentCard.Builder() - .name("prime_agent") - .description("Stub agent metadata used for third-party A2A demo") - .url(primeAgentBaseUrl) - .version("1.0.0") - .capabilities(capabilities) - .defaultInputModes(List.of("text")) - .defaultOutputModes(List.of("text")) - .skills(List.of()) - .security(List.of()) - .build(); - A2AClient client = new A2AClient(agentCard, new JdkA2AHttpClient(), /* defaultHeaders= */ null); - return RemoteA2AAgent.builder() - .name(agentCard.name()) - .agentCardOrSource(agentCard) - .a2aClient(client) - .build(); - } - - private A2AAgent() {} -} diff --git a/contrib/samples/a2a_basic/A2AAgentRun.java b/contrib/samples/a2a_basic/A2AAgentRun.java deleted file mode 100644 index 406a8dcbc..000000000 --- a/contrib/samples/a2a_basic/A2AAgentRun.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.example.a2a_basic; - -import com.google.adk.agents.BaseAgent; -import com.google.adk.agents.LlmAgent; -import com.google.adk.agents.RunConfig; -import com.google.adk.artifacts.InMemoryArtifactService; -import com.google.adk.events.Event; -import com.google.adk.runner.Runner; -import com.google.adk.sessions.InMemorySessionService; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.genai.types.Content; -import com.google.genai.types.Part; -import io.reactivex.rxjava3.core.Flowable; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** Main class to demonstrate running the A2A agent with sequential inputs. */ -public final class A2AAgentRun { - private final String userId; - private final String sessionId; - private final Runner runner; - - public A2AAgentRun(BaseAgent agent) { - this.userId = "test_user"; - String appName = "A2AAgentApp"; - this.sessionId = UUID.randomUUID().toString(); - - InMemoryArtifactService artifactService = new InMemoryArtifactService(); - InMemorySessionService sessionService = new InMemorySessionService(); - this.runner = - new Runner(agent, appName, artifactService, sessionService, /* memoryService= */ null); - - ConcurrentMap initialState = new ConcurrentHashMap<>(); - var unused = - sessionService.createSession(appName, userId, initialState, sessionId).blockingGet(); - } - - private List run(String prompt) { - System.out.println("\n--------------------------------------------------"); - System.out.println("You> " + prompt); - Content userMessage = - Content.builder() - .role("user") - .parts(ImmutableList.of(Part.builder().text(prompt).build())) - .build(); - return processRunRequest(userMessage); - } - - private List processRunRequest(Content inputContent) { - RunConfig runConfig = RunConfig.builder().build(); - Flowable eventStream = - this.runner.runAsync(this.userId, this.sessionId, inputContent, runConfig); - List agentEvents = Lists.newArrayList(eventStream.blockingIterable()); - System.out.println("Agent>"); - for (Event event : agentEvents) { - if (event.content().isPresent() && event.content().get().parts().isPresent()) { - event - .content() - .get() - .parts() - .get() - .forEach( - part -> { - if (part.text().isPresent()) { - System.out.println(" Text: " + part.text().get().stripTrailing()); - } - }); - } - if (event.actions() != null && event.actions().transferToAgent().isPresent()) { - System.out.println(" Actions: transferTo=" + event.actions().transferToAgent().get()); - } - System.out.println(" Raw Event: " + event); - } - return agentEvents; - } - - public static void main(String[] args) { - String primeAgentUrl = args.length > 0 ? args[0] : "http://localhost:9876/a2a/prime_agent"; - LlmAgent agent = A2AAgent.createRootAgent(primeAgentUrl); - A2AAgentRun a2aRun = new A2AAgentRun(agent); - - // First user input - System.out.println("Running turn 1"); - a2aRun.run("Roll a dice of 6 sides."); - - // Follow-up input triggers the remote prime agent so the A2A request is logged. - System.out.println("Running turn 2"); - a2aRun.run("Is this number a prime number?"); - } -} diff --git a/contrib/samples/a2a_basic/pom.xml b/contrib/samples/a2a_basic/pom.xml index b4618b206..a49b950a5 100644 --- a/contrib/samples/a2a_basic/pom.xml +++ b/contrib/samples/a2a_basic/pom.xml @@ -50,25 +50,7 @@ true - - org.codehaus.mojo - build-helper-maven-plugin - 3.6.0 - - - add-source - generate-sources - - add-source - - - - . - - - - - + org.codehaus.mojo exec-maven-plugin diff --git a/contrib/samples/a2a_remote/pom.xml b/contrib/samples/a2a_remote/pom.xml index 26bb6ff1d..ef7b2952d 100644 --- a/contrib/samples/a2a_remote/pom.xml +++ b/contrib/samples/a2a_remote/pom.xml @@ -95,25 +95,6 @@ spring-boot-maven-plugin ${spring-boot.version} - - org.codehaus.mojo - build-helper-maven-plugin - 3.6.0 - - - add-source - generate-sources - - add-source - - - - . - - - - - org.codehaus.mojo exec-maven-plugin diff --git a/contrib/samples/a2a_remote/remote_prime_agent/Agent.java b/contrib/samples/a2a_remote/remote_prime_agent/Agent.java deleted file mode 100644 index a0072e8e3..000000000 --- a/contrib/samples/a2a_remote/remote_prime_agent/Agent.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.google.adk.samples.a2a_remote.remote_prime_agent; - -import static java.util.stream.Collectors.joining; - -import com.google.adk.agents.LlmAgent; -import com.google.adk.tools.FunctionTool; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.flogger.GoogleLogger; -import io.reactivex.rxjava3.core.Maybe; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** Agent that can check whether numbers are prime. */ -public final class Agent { - - private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); - - public static ImmutableMap checkPrime(List nums) { - logger.atInfo().log("checkPrime called with nums=%s", nums); - Set primes = new HashSet<>(); - for (int num : nums) { - if (num <= 1) { - continue; - } - boolean isPrime = true; - for (int i = 2; i <= Math.sqrt(num); i++) { - if (num % i == 0) { - isPrime = false; - break; - } - } - if (isPrime) { - primes.add(num); - } - } - String result; - if (primes.isEmpty()) { - result = "No prime numbers found."; - } else if (primes.size() == 1) { - int only = primes.iterator().next(); - // Per request: singular phrasing without article - result = only + " is prime number."; - } else { - result = primes.stream().map(String::valueOf).collect(joining(", ")) + " are prime numbers."; - } - logger.atInfo().log("checkPrime result=%s", result); - return ImmutableMap.of("result", result); - } - - public static final LlmAgent ROOT_AGENT = - LlmAgent.builder() - .model("gemini-2.5-pro") - .name("check_prime_agent") - .description("check prime agent that can check whether numbers are prime.") - .instruction( - """ - You check whether numbers are prime. - - If the last user message contains numbers, call checkPrime exactly once with exactly - those integers as a list (e.g., [2]). Never add other numbers. Do not ask for - clarification. Return only the tool's result. - - Always pass a list of integers to the tool (use a single-element list for one - number). Never pass strings. - """) - // Log the exact contents passed to the LLM request for verification - .beforeModelCallback( - (callbackContext, llmRequest) -> { - try { - logger.atInfo().log( - "Invocation events (count=%d): %s", - callbackContext.events().size(), callbackContext.events()); - } catch (Throwable t) { - logger.atWarning().withCause(t).log("BeforeModel logging error"); - } - return Maybe.empty(); - }) - .afterModelCallback( - (callbackContext, llmResponse) -> { - try { - String content = - llmResponse.content().map(Object::toString).orElse(""); - logger.atInfo().log("AfterModel content=%s", content); - llmResponse - .errorMessage() - .ifPresent( - error -> - logger.atInfo().log( - "AfterModel errorMessage=%s", error.replace("\n", "\\n"))); - } catch (Throwable t) { - logger.atWarning().withCause(t).log("AfterModel logging error"); - } - return Maybe.empty(); - }) - .tools(ImmutableList.of(FunctionTool.create(Agent.class, "checkPrime"))) - .build(); - - private Agent() {} -} diff --git a/contrib/samples/a2a_remote/remote_prime_agent/agent.json b/contrib/samples/a2a_remote/remote_prime_agent/agent.json deleted file mode 100644 index 87f2d9ecc..000000000 --- a/contrib/samples/a2a_remote/remote_prime_agent/agent.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "capabilities": {}, - "defaultInputModes": ["text/plain"], - "defaultOutputModes": ["application/json"], - "description": "An agent specialized in checking whether numbers are prime. It can efficiently determine the primality of individual numbers or lists of numbers.", - "name": "check_prime_agent", - "skills": [ - { - "id": "prime_checking", - "name": "Prime Number Checking", - "description": "Check if numbers in a list are prime using efficient mathematical algorithms", - "tags": ["mathematical", "computation", "prime", "numbers"] - } - ], - "url": "http://localhost:8080/a2a/prime_agent", - "version": "1.0.0" -} From 257f65e03937a5c75cac95e80068f4d54c04cc04 Mon Sep 17 00:00:00 2001 From: "Panek, Tomasz" Date: Fri, 17 Oct 2025 19:38:00 +0200 Subject: [PATCH 04/10] rearanging folders for eclipse --- a2a/{webservice => google-adk-a2a-webservice}/pom.xml | 0 .../main/java/com/google/adk/webservice/A2ARemoteApplication.java | 0 .../java/com/google/adk/webservice/A2ARemoteConfiguration.java | 0 .../main/java/com/google/adk/webservice/A2ARemoteController.java | 0 .../src/main/java/com/google/adk/webservice/A2ARemoteService.java | 0 a2a/{ => google-adk-a2a}/README.md | 0 a2a/{ => google-adk-a2a}/pom.xml | 0 .../src/main/java/com/google/adk/a2a/A2AClient.java | 0 .../src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java | 0 .../src/main/java/com/google/adk/a2a/RemoteA2AAgent.java | 0 .../com/google/adk/a2a/converters/ConversationPreprocessor.java | 0 .../main/java/com/google/adk/a2a/converters/EventConverter.java | 0 .../main/java/com/google/adk/a2a/converters/PartConverter.java | 0 .../main/java/com/google/adk/a2a/converters/RequestConverter.java | 0 .../java/com/google/adk/a2a/converters/ResponseConverter.java | 0 .../src/test/java/com/google/adk/a2a/EventConverterTest.java | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename a2a/{webservice => google-adk-a2a-webservice}/pom.xml (100%) rename a2a/{webservice => google-adk-a2a-webservice}/src/main/java/com/google/adk/webservice/A2ARemoteApplication.java (100%) rename a2a/{webservice => google-adk-a2a-webservice}/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java (100%) rename a2a/{webservice => google-adk-a2a-webservice}/src/main/java/com/google/adk/webservice/A2ARemoteController.java (100%) rename a2a/{webservice => google-adk-a2a-webservice}/src/main/java/com/google/adk/webservice/A2ARemoteService.java (100%) rename a2a/{ => google-adk-a2a}/README.md (100%) rename a2a/{ => google-adk-a2a}/pom.xml (100%) rename a2a/{ => google-adk-a2a}/src/main/java/com/google/adk/a2a/A2AClient.java (100%) rename a2a/{ => google-adk-a2a}/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java (100%) rename a2a/{ => google-adk-a2a}/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java (100%) rename a2a/{ => google-adk-a2a}/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java (100%) rename a2a/{ => google-adk-a2a}/src/main/java/com/google/adk/a2a/converters/EventConverter.java (100%) rename a2a/{ => google-adk-a2a}/src/main/java/com/google/adk/a2a/converters/PartConverter.java (100%) rename a2a/{ => google-adk-a2a}/src/main/java/com/google/adk/a2a/converters/RequestConverter.java (100%) rename a2a/{ => google-adk-a2a}/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java (100%) rename a2a/{ => google-adk-a2a}/src/test/java/com/google/adk/a2a/EventConverterTest.java (100%) diff --git a/a2a/webservice/pom.xml b/a2a/google-adk-a2a-webservice/pom.xml similarity index 100% rename from a2a/webservice/pom.xml rename to a2a/google-adk-a2a-webservice/pom.xml diff --git a/a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteApplication.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteApplication.java similarity index 100% rename from a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteApplication.java rename to a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteApplication.java diff --git a/a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java similarity index 100% rename from a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java rename to a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java diff --git a/a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java similarity index 100% rename from a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java rename to a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java diff --git a/a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteService.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteService.java similarity index 100% rename from a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteService.java rename to a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteService.java diff --git a/a2a/README.md b/a2a/google-adk-a2a/README.md similarity index 100% rename from a2a/README.md rename to a2a/google-adk-a2a/README.md diff --git a/a2a/pom.xml b/a2a/google-adk-a2a/pom.xml similarity index 100% rename from a2a/pom.xml rename to a2a/google-adk-a2a/pom.xml diff --git a/a2a/src/main/java/com/google/adk/a2a/A2AClient.java b/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/A2AClient.java similarity index 100% rename from a2a/src/main/java/com/google/adk/a2a/A2AClient.java rename to a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/A2AClient.java diff --git a/a2a/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java b/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java similarity index 100% rename from a2a/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java rename to a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java diff --git a/a2a/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java b/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java similarity index 100% rename from a2a/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java rename to a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java diff --git a/a2a/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java b/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java similarity index 100% rename from a2a/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java rename to a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java diff --git a/a2a/src/main/java/com/google/adk/a2a/converters/EventConverter.java b/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/EventConverter.java similarity index 100% rename from a2a/src/main/java/com/google/adk/a2a/converters/EventConverter.java rename to a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/EventConverter.java diff --git a/a2a/src/main/java/com/google/adk/a2a/converters/PartConverter.java b/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/PartConverter.java similarity index 100% rename from a2a/src/main/java/com/google/adk/a2a/converters/PartConverter.java rename to a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/PartConverter.java diff --git a/a2a/src/main/java/com/google/adk/a2a/converters/RequestConverter.java b/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/RequestConverter.java similarity index 100% rename from a2a/src/main/java/com/google/adk/a2a/converters/RequestConverter.java rename to a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/RequestConverter.java diff --git a/a2a/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java b/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java similarity index 100% rename from a2a/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java rename to a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java diff --git a/a2a/src/test/java/com/google/adk/a2a/EventConverterTest.java b/a2a/google-adk-a2a/src/test/java/com/google/adk/a2a/EventConverterTest.java similarity index 100% rename from a2a/src/test/java/com/google/adk/a2a/EventConverterTest.java rename to a2a/google-adk-a2a/src/test/java/com/google/adk/a2a/EventConverterTest.java From c383a4122c7e16dcd1b57ec27cfd97876c51ed5e Mon Sep 17 00:00:00 2001 From: "Panek, Tomasz" Date: Mon, 20 Oct 2025 14:09:28 +0200 Subject: [PATCH 05/10] changing folderz structure --- .../README.md | 2 +- .../pom.xml | 4 ++-- .../java/com/google/adk/a2a/A2AClient.java | 0 .../adk/a2a/A2ASendMessageExecutor.java | 13 +++++++++- .../com/google/adk/a2a/RemoteA2AAgent.java | 2 ++ .../converters/ConversationPreprocessor.java | 2 +- .../adk/a2a/converters/EventConverter.java | 2 +- .../adk/a2a/converters/PartConverter.java | 2 +- .../adk/a2a/converters/RequestConverter.java | 2 +- .../adk/a2a/converters/ResponseConverter.java | 2 +- .../google/adk/a2a/EventConverterTest.java | 2 ++ a2a/google-adk-a2a-webservice/pom.xml | 4 ++-- .../webservice/A2ARemoteConfiguration.java | 7 ++++-- .../adk/webservice/A2ARemoteController.java | 24 ++++++++++++++++--- .../adk/webservice/A2ARemoteService.java | 7 +++++- a2a/pom.xml | 21 ++++++++++++++++ 16 files changed, 79 insertions(+), 17 deletions(-) rename a2a/{google-adk-a2a => google-adk-a2a-core}/README.md (99%) rename a2a/{google-adk-a2a => google-adk-a2a-core}/pom.xml (97%) rename a2a/{google-adk-a2a => google-adk-a2a-core}/src/main/java/com/google/adk/a2a/A2AClient.java (100%) rename a2a/{google-adk-a2a => google-adk-a2a-core}/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java (95%) rename a2a/{google-adk-a2a => google-adk-a2a-core}/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java (99%) rename a2a/{google-adk-a2a => google-adk-a2a-core}/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java (98%) rename a2a/{google-adk-a2a => google-adk-a2a-core}/src/main/java/com/google/adk/a2a/converters/EventConverter.java (99%) rename a2a/{google-adk-a2a => google-adk-a2a-core}/src/main/java/com/google/adk/a2a/converters/PartConverter.java (99%) rename a2a/{google-adk-a2a => google-adk-a2a-core}/src/main/java/com/google/adk/a2a/converters/RequestConverter.java (99%) rename a2a/{google-adk-a2a => google-adk-a2a-core}/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java (99%) rename a2a/{google-adk-a2a => google-adk-a2a-core}/src/test/java/com/google/adk/a2a/EventConverterTest.java (97%) create mode 100644 a2a/pom.xml diff --git a/a2a/google-adk-a2a/README.md b/a2a/google-adk-a2a-core/README.md similarity index 99% rename from a2a/google-adk-a2a/README.md rename to a2a/google-adk-a2a-core/README.md index a5ae45008..82f1a13ae 100644 --- a/a2a/google-adk-a2a/README.md +++ b/a2a/google-adk-a2a-core/README.md @@ -177,7 +177,7 @@ curl -X POST http://localhost:8081/a2a/remote/v1/message:send \ "kind": "message", "contextId": "cli-demo-context", "messageId": "cli-check-2", - "role": "USER", + "role": "user", "parts": [ { "kind": "text", "text": "Is 2 prime?" } ] diff --git a/a2a/google-adk-a2a/pom.xml b/a2a/google-adk-a2a-core/pom.xml similarity index 97% rename from a2a/google-adk-a2a/pom.xml rename to a2a/google-adk-a2a-core/pom.xml index 61af36efd..3fb16c7a0 100644 --- a/a2a/google-adk-a2a/pom.xml +++ b/a2a/google-adk-a2a-core/pom.xml @@ -4,11 +4,11 @@ com.google.adk - google-adk-parent + google-adk-a2a 0.3.1-SNAPSHOT - google-adk-a2a + google-adk-a2a-core jar Google ADK A2A Integration diff --git a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/A2AClient.java b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2AClient.java similarity index 100% rename from a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/A2AClient.java rename to a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2AClient.java diff --git a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java similarity index 95% rename from a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java rename to a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java index 4beef8432..cb6c756b6 100644 --- a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java +++ b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java @@ -3,6 +3,9 @@ import static com.google.common.base.Strings.isNullOrEmpty; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import com.google.adk.a2a.converters.ConversationPreprocessor; +import com.google.adk.a2a.converters.RequestConverter; +import com.google.adk.a2a.converters.ResponseConverter; import com.google.adk.agents.BaseAgent; import com.google.adk.agents.RunConfig; import com.google.adk.artifacts.InMemoryArtifactService; @@ -13,6 +16,7 @@ import com.google.adk.sessions.Session; import com.google.common.collect.ImmutableList; import com.google.genai.types.Content; +import io.a2a.spec.AgentCard; import io.a2a.spec.Message; import io.a2a.spec.TextPart; import io.reactivex.rxjava3.core.Completable; @@ -49,6 +53,7 @@ Single> execute( @Nullable private final Duration agentTimeout; private static final RunConfig DEFAULT_RUN_CONFIG = RunConfig.builder().setStreamingMode(RunConfig.StreamingMode.NONE).setMaxLlmCalls(20).build(); + private AgentCard agentCard; public A2ASendMessageExecutor(InMemorySessionService sessionService, String appName) { this.sessionService = sessionService; @@ -57,7 +62,8 @@ public A2ASendMessageExecutor(InMemorySessionService sessionService, String appN this.agentTimeout = null; } - public A2ASendMessageExecutor(BaseAgent agent, String appName, Duration agentTimeout) { + public A2ASendMessageExecutor( + BaseAgent agent, String appName, Duration agentTimeout, AgentCard agentCard) { InMemorySessionService sessionService = new InMemorySessionService(); Runner runnerInstance = new Runner( @@ -70,6 +76,7 @@ public A2ASendMessageExecutor(BaseAgent agent, String appName, Duration agentTim this.appName = appName; this.runner = runnerInstance; this.agentTimeout = agentTimeout; + this.agentCard = agentCard; } public Single execute( @@ -296,4 +303,8 @@ private static boolean isTimeout(@Nullable Throwable throwable) { } return false; } + + public AgentCard getAgentCard() { + return agentCard; + } } diff --git a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java similarity index 99% rename from a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java rename to a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java index 3fd4fa552..55ada25e4 100644 --- a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java +++ b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/RemoteA2AAgent.java @@ -4,6 +4,8 @@ import static com.google.common.base.Strings.nullToEmpty; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.adk.a2a.converters.EventConverter; +import com.google.adk.a2a.converters.ResponseConverter; import com.google.adk.agents.BaseAgent; import com.google.adk.agents.Callbacks; import com.google.adk.agents.InvocationContext; diff --git a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java similarity index 98% rename from a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java rename to a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java index 91b9237ac..d54e67a18 100644 --- a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java +++ b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/ConversationPreprocessor.java @@ -1,4 +1,4 @@ -package com.google.adk.a2a; +package com.google.adk.a2a.converters; import com.google.adk.events.Event; import com.google.common.collect.ImmutableList; diff --git a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/EventConverter.java b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/EventConverter.java similarity index 99% rename from a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/EventConverter.java rename to a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/EventConverter.java index 19d7d5ca9..848f5264f 100644 --- a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/EventConverter.java +++ b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/EventConverter.java @@ -1,4 +1,4 @@ -package com.google.adk.a2a; +package com.google.adk.a2a.converters; import com.google.adk.agents.InvocationContext; import com.google.adk.events.Event; diff --git a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/PartConverter.java b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/PartConverter.java similarity index 99% rename from a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/PartConverter.java rename to a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/PartConverter.java index 38d0e7910..0ac1cefb5 100644 --- a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/PartConverter.java +++ b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/PartConverter.java @@ -1,4 +1,4 @@ -package com.google.adk.a2a; +package com.google.adk.a2a.converters; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/RequestConverter.java b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/RequestConverter.java similarity index 99% rename from a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/RequestConverter.java rename to a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/RequestConverter.java index 5936f64c2..c7d9deea4 100644 --- a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/RequestConverter.java +++ b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/RequestConverter.java @@ -1,4 +1,4 @@ -package com.google.adk.a2a; +package com.google.adk.a2a.converters; import com.google.adk.events.Event; import com.google.common.collect.ImmutableList; diff --git a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java similarity index 99% rename from a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java rename to a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java index 516a61bc0..61c61ebd4 100644 --- a/a2a/google-adk-a2a/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java +++ b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/converters/ResponseConverter.java @@ -1,4 +1,4 @@ -package com.google.adk.a2a; +package com.google.adk.a2a.converters; import com.google.adk.events.Event; import com.google.genai.types.Content; diff --git a/a2a/google-adk-a2a/src/test/java/com/google/adk/a2a/EventConverterTest.java b/a2a/google-adk-a2a-core/src/test/java/com/google/adk/a2a/EventConverterTest.java similarity index 97% rename from a2a/google-adk-a2a/src/test/java/com/google/adk/a2a/EventConverterTest.java rename to a2a/google-adk-a2a-core/src/test/java/com/google/adk/a2a/EventConverterTest.java index 0593120fd..3cff47899 100644 --- a/a2a/google-adk-a2a/src/test/java/com/google/adk/a2a/EventConverterTest.java +++ b/a2a/google-adk-a2a-core/src/test/java/com/google/adk/a2a/EventConverterTest.java @@ -2,6 +2,8 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.adk.a2a.converters.EventConverter; +import com.google.adk.a2a.converters.PartConverter; import com.google.adk.agents.BaseAgent; import com.google.adk.agents.InvocationContext; import com.google.adk.agents.RunConfig; diff --git a/a2a/google-adk-a2a-webservice/pom.xml b/a2a/google-adk-a2a-webservice/pom.xml index b929afab9..cf97796b9 100644 --- a/a2a/google-adk-a2a-webservice/pom.xml +++ b/a2a/google-adk-a2a-webservice/pom.xml @@ -6,7 +6,7 @@ com.google.adk - google-adk-parent + google-adk-a2a 0.3.1-SNAPSHOT @@ -23,7 +23,7 @@ com.google.adk - google-adk-a2a + google-adk-a2a-core ${project.version} diff --git a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java index 3c911bad9..2e3ffbeb6 100644 --- a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java +++ b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java @@ -2,6 +2,7 @@ import com.google.adk.a2a.A2ASendMessageExecutor; import com.google.adk.agents.BaseAgent; +import io.a2a.spec.AgentCard; import java.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,11 +37,13 @@ public class A2ARemoteConfiguration { public A2ASendMessageExecutor a2aSendMessageExecutor( BaseAgent agent, @Value("${a2a.remote.appName:" + DEFAULT_APP_NAME + "}") String appName, - @Value("${a2a.remote.timeoutSeconds:" + DEFAULT_TIMEOUT_SECONDS + "}") long timeoutSeconds) { + @Value("${a2a.remote.timeoutSeconds:" + DEFAULT_TIMEOUT_SECONDS + "}") long timeoutSeconds, + AgentCard agentCard) { logger.info( "Initializing A2A send message executor for appName {} with timeout {}s", appName, timeoutSeconds); - return new A2ASendMessageExecutor(agent, appName, Duration.ofSeconds(timeoutSeconds)); + return new A2ASendMessageExecutor( + agent, appName, Duration.ofSeconds(timeoutSeconds), agentCard); } } diff --git a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java index fbb7cf108..312205cf3 100644 --- a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java +++ b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java @@ -1,9 +1,12 @@ package com.google.adk.webservice; +import io.a2a.spec.AgentCard; import io.a2a.spec.SendMessageRequest; import io.a2a.spec.SendMessageResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -23,13 +26,28 @@ public A2ARemoteController(A2ARemoteService service) { } @PostMapping( - path = "/v1/message:send", + path = {"/*"}, + consumes = "application/json", + produces = "application/json") + public SendMessageResponse sendMessageDebug(@RequestBody SendMessageRequest request) { + logger.info("Received remote A2A request: {}", request); + return null; + } + + @PostMapping( + path = {"/message", "/message/"}, consumes = "application/json", produces = "application/json") public SendMessageResponse sendMessage(@RequestBody SendMessageRequest request) { - logger.debug("Received remote A2A request: {}", request); + logger.info("Received remote A2A request: {}", request); SendMessageResponse response = service.handle(request); - logger.debug("Responding with remote A2A payload: {}", response); + logger.info("Responding with remote A2A payload: {}", response); return response; } + + /** Get agent card information */ + @GetMapping(path = "/message/.well-known/agent-card.json", produces = "application/json") + public ResponseEntity getAgentCard() { + return ResponseEntity.ok(service.getAgentCard()); + } } diff --git a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteService.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteService.java index 6f4613bfe..71aad0a04 100644 --- a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteService.java +++ b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteService.java @@ -1,7 +1,8 @@ package com.google.adk.webservice; import com.google.adk.a2a.A2ASendMessageExecutor; -import com.google.adk.a2a.ResponseConverter; +import com.google.adk.a2a.converters.ResponseConverter; +import io.a2a.spec.AgentCard; import io.a2a.spec.JSONRPCError; import io.a2a.spec.Message; import io.a2a.spec.MessageSendParams; @@ -85,4 +86,8 @@ private static SendMessageResponse errorResponse(SendMessageRequest request, Thr JSONRPCError jsonrpcError = new JSONRPCError(ERROR_CODE_INTERNAL_ERROR, message, null); return new SendMessageResponse(request != null ? request.getId() : null, jsonrpcError); } + + public AgentCard getAgentCard() { + return executor.getAgentCard(); + } } diff --git a/a2a/pom.xml b/a2a/pom.xml new file mode 100644 index 000000000..7911e4118 --- /dev/null +++ b/a2a/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + + + com.google.adk + google-adk-parent + 0.3.1-SNAPSHOT + + + + google-adk-a2a + google-adk-a2a + pom + + + google-adk-a2a-core + google-adk-a2a-webservice + + + + From 21d7f527b7d60c2e6f7f8d1e5c66e1399a951232 Mon Sep 17 00:00:00 2001 From: "Panek, Tomasz" Date: Wed, 22 Oct 2025 16:19:07 +0200 Subject: [PATCH 06/10] adding support for agent cards --- a2a/google-adk-a2a-core/pom.xml | 2 +- .../adk/a2a/A2ASendMessageExecutor.java | 12 +++++++- a2a/google-adk-a2a-webservice/pom.xml | 2 +- .../webservice/A2ARemoteConfiguration.java | 3 +- .../adk/webservice/A2ARemoteController.java | 17 +++-------- contrib/samples/a2a_basic/pom.xml | 2 +- contrib/samples/a2a_remote/pom.xml | 8 ++--- .../a2a_remote/RemoteA2AApplication.java | 30 +++++++++++++++++++ pom.xml | 3 +- 9 files changed, 54 insertions(+), 25 deletions(-) diff --git a/a2a/google-adk-a2a-core/pom.xml b/a2a/google-adk-a2a-core/pom.xml index 3fb16c7a0..1ad23c111 100644 --- a/a2a/google-adk-a2a-core/pom.xml +++ b/a2a/google-adk-a2a-core/pom.xml @@ -7,7 +7,7 @@ google-adk-a2a 0.3.1-SNAPSHOT - + google-adk-a2a-core jar diff --git a/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java index cb6c756b6..9f724e6b2 100644 --- a/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java +++ b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java @@ -12,6 +12,7 @@ import com.google.adk.events.Event; import com.google.adk.memory.InMemoryMemoryService; import com.google.adk.runner.Runner; +import com.google.adk.sessions.BaseSessionService; import com.google.adk.sessions.InMemorySessionService; import com.google.adk.sessions.Session; import com.google.common.collect.ImmutableList; @@ -47,7 +48,7 @@ Single> execute( String invocationId); } - private final InMemorySessionService sessionService; + private final BaseSessionService sessionService; private final String appName; @Nullable private final Runner runner; @Nullable private final Duration agentTimeout; @@ -62,6 +63,15 @@ public A2ASendMessageExecutor(InMemorySessionService sessionService, String appN this.agentTimeout = null; } + public A2ASendMessageExecutor( + Runner runner, String appName, Duration agentTimeout, AgentCard agentCard) { + this.sessionService = runner.sessionService(); + this.appName = appName; + this.runner = runner; + this.agentTimeout = agentTimeout; + this.agentCard = agentCard; + } + public A2ASendMessageExecutor( BaseAgent agent, String appName, Duration agentTimeout, AgentCard agentCard) { InMemorySessionService sessionService = new InMemorySessionService(); diff --git a/a2a/google-adk-a2a-webservice/pom.xml b/a2a/google-adk-a2a-webservice/pom.xml index cf97796b9..87893da42 100644 --- a/a2a/google-adk-a2a-webservice/pom.xml +++ b/a2a/google-adk-a2a-webservice/pom.xml @@ -24,7 +24,7 @@ com.google.adk google-adk-a2a-core - ${project.version} + 0.3.1-SNAPSHOT org.springframework.boot diff --git a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java index 2e3ffbeb6..3793a9e5f 100644 --- a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java +++ b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java @@ -7,7 +7,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -33,7 +32,7 @@ public class A2ARemoteConfiguration { private static final String DEFAULT_APP_NAME = "a2a-remote-service"; private static final long DEFAULT_TIMEOUT_SECONDS = 15L; - @Bean + // @Bean public A2ASendMessageExecutor a2aSendMessageExecutor( BaseAgent agent, @Value("${a2a.remote.appName:" + DEFAULT_APP_NAME + "}") String appName, diff --git a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java index 312205cf3..45991a82c 100644 --- a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java +++ b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteController.java @@ -26,27 +26,18 @@ public A2ARemoteController(A2ARemoteService service) { } @PostMapping( - path = {"/*"}, - consumes = "application/json", - produces = "application/json") - public SendMessageResponse sendMessageDebug(@RequestBody SendMessageRequest request) { - logger.info("Received remote A2A request: {}", request); - return null; - } - - @PostMapping( - path = {"/message", "/message/"}, + path = "/v1/message:send", consumes = "application/json", produces = "application/json") public SendMessageResponse sendMessage(@RequestBody SendMessageRequest request) { - logger.info("Received remote A2A request: {}", request); + logger.debug("Received remote A2A request: {}", request); SendMessageResponse response = service.handle(request); - logger.info("Responding with remote A2A payload: {}", response); + logger.debug("Responding with remote A2A payload: {}", response); return response; } /** Get agent card information */ - @GetMapping(path = "/message/.well-known/agent-card.json", produces = "application/json") + @GetMapping(path = "/v1/.well-known/agent-card.json", produces = "application/json") public ResponseEntity getAgentCard() { return ResponseEntity.ok(service.getAgentCard()); } diff --git a/contrib/samples/a2a_basic/pom.xml b/contrib/samples/a2a_basic/pom.xml index a49b950a5..2e94e16c0 100644 --- a/contrib/samples/a2a_basic/pom.xml +++ b/contrib/samples/a2a_basic/pom.xml @@ -28,7 +28,7 @@ com.google.adk - google-adk-a2a + google-adk-a2a-core ${google-adk-a2a.version} diff --git a/contrib/samples/a2a_remote/pom.xml b/contrib/samples/a2a_remote/pom.xml index ef7b2952d..67557c57c 100644 --- a/contrib/samples/a2a_remote/pom.xml +++ b/contrib/samples/a2a_remote/pom.xml @@ -9,7 +9,7 @@ google-adk-parent 0.3.1-SNAPSHOT - + google-adk-sample-a2a-remote Google ADK - Sample - A2A Remote Prime Service Spring Boot service that exposes the remote prime-check agent over the A2A REST interface. @@ -48,14 +48,14 @@ com.google.adk - google-adk-a2a - ${project.version} + google-adk-a2a-core + 0.3.1-SNAPSHOT com.google.adk google-adk-a2a-webservice - ${project.version} + 0.3.1-SNAPSHOT diff --git a/contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/RemoteA2AApplication.java b/contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/RemoteA2AApplication.java index 53be8d1d0..8f7c89562 100644 --- a/contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/RemoteA2AApplication.java +++ b/contrib/samples/a2a_remote/src/main/java/com/google/adk/samples/a2a_remote/RemoteA2AApplication.java @@ -3,6 +3,10 @@ import com.google.adk.agents.BaseAgent; import com.google.adk.samples.a2a_remote.remote_prime_agent.Agent; import com.google.adk.webservice.A2ARemoteConfiguration; +import io.a2a.spec.AgentCapabilities; +import io.a2a.spec.AgentCard; +import io.a2a.spec.AgentSkill; +import java.util.List; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @@ -21,4 +25,30 @@ public static void main(String[] args) { public BaseAgent primeAgent() { return Agent.ROOT_AGENT; } + + @Bean + public AgentCard agentCard() { + return new AgentCard.Builder() + .name("check_prime_agent") + .capabilities(new AgentCapabilities(false, false, false, List.of())) + .description( + "An agent specialized in checking whether numbers are prime. It can efficiently determine the primality of individual numbers or lists of numbers.") + .url("http://localhost:8080/a2a/remote/v1/message:send") + .version("1.0.0") + .defaultInputModes(List.of("text/plain")) + .defaultOutputModes(List.of("application/json")) + .skills( + List.of( + new AgentSkill( + "prime_checking", + "Prime Number Checking", + "Check if numbers in a list are prime using efficient mathematical algorithms", + List.of("mathematical", "computation", "prime", "numbers"), + List.of(), + List.of(), + List.of(), + List.of()))) + .security(List.of()) + .build(); + } } diff --git a/pom.xml b/pom.xml index d174f6ad8..0f52647c7 100644 --- a/pom.xml +++ b/pom.xml @@ -28,11 +28,10 @@ core dev maven_plugin + a2a contrib/langchain4j contrib/samples tutorials/city-time-weather - a2a - a2a/webservice From fd8d474a8f5d627f2eb442a638d8e79fae440915 Mon Sep 17 00:00:00 2001 From: "Panek, Tomasz" Date: Wed, 22 Oct 2025 17:11:12 +0200 Subject: [PATCH 07/10] restoring bean creation --- .../java/com/google/adk/webservice/A2ARemoteConfiguration.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java index 3793a9e5f..2e3ffbeb6 100644 --- a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java +++ b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java @@ -7,6 +7,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -32,7 +33,7 @@ public class A2ARemoteConfiguration { private static final String DEFAULT_APP_NAME = "a2a-remote-service"; private static final long DEFAULT_TIMEOUT_SECONDS = 15L; - // @Bean + @Bean public A2ASendMessageExecutor a2aSendMessageExecutor( BaseAgent agent, @Value("${a2a.remote.appName:" + DEFAULT_APP_NAME + "}") String appName, From a4c8a3a2c36c46bee8874e32a2c578f55e970a22 Mon Sep 17 00:00:00 2001 From: "Panek, Tomasz" Date: Wed, 22 Oct 2025 17:29:42 +0200 Subject: [PATCH 08/10] fixing client --- .../src/main/java/com/example/a2a_basic/A2AAgentRun.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgentRun.java b/contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgentRun.java index 406a8dcbc..428817dfe 100644 --- a/contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgentRun.java +++ b/contrib/samples/a2a_basic/src/main/java/com/example/a2a_basic/A2AAgentRun.java @@ -78,7 +78,7 @@ private List processRunRequest(Content inputContent) { } public static void main(String[] args) { - String primeAgentUrl = args.length > 0 ? args[0] : "http://localhost:9876/a2a/prime_agent"; + String primeAgentUrl = args.length > 0 ? args[0] : "http://localhost:8080/a2a/remote"; LlmAgent agent = A2AAgent.createRootAgent(primeAgentUrl); A2AAgentRun a2aRun = new A2AAgentRun(agent); From d2b8fa1d49fb5b346638454a979c5682da40d030 Mon Sep 17 00:00:00 2001 From: "Panek, Tomasz" Date: Thu, 23 Oct 2025 10:39:58 +0200 Subject: [PATCH 09/10] making method for creating executor more general --- .../adk/webservice/A2ARemoteConfiguration.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java index 2e3ffbeb6..80a721b19 100644 --- a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java +++ b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java @@ -2,10 +2,12 @@ import com.google.adk.a2a.A2ASendMessageExecutor; import com.google.adk.agents.BaseAgent; +import com.google.adk.runner.Runner; import io.a2a.spec.AgentCard; import java.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -35,7 +37,8 @@ public class A2ARemoteConfiguration { @Bean public A2ASendMessageExecutor a2aSendMessageExecutor( - BaseAgent agent, + @Autowired(required = false) BaseAgent agent, + @Autowired(required = false) Runner runner, @Value("${a2a.remote.appName:" + DEFAULT_APP_NAME + "}") String appName, @Value("${a2a.remote.timeoutSeconds:" + DEFAULT_TIMEOUT_SECONDS + "}") long timeoutSeconds, AgentCard agentCard) { @@ -43,7 +46,13 @@ public A2ASendMessageExecutor a2aSendMessageExecutor( "Initializing A2A send message executor for appName {} with timeout {}s", appName, timeoutSeconds); - return new A2ASendMessageExecutor( - agent, appName, Duration.ofSeconds(timeoutSeconds), agentCard); + if (agent != null) { + return new A2ASendMessageExecutor( + agent, appName, Duration.ofSeconds(timeoutSeconds), agentCard); + } else if (runner != null) { + return new A2ASendMessageExecutor( + runner, appName, Duration.ofSeconds(timeoutSeconds), agentCard); + } + throw new IllegalStateException("Neither BaseAgent nor Runner is available!"); } } From 13bb6d3db2f78205632dfcfc9d570a2a22cb3143 Mon Sep 17 00:00:00 2001 From: "Panek, Tomasz" Date: Fri, 24 Oct 2025 12:31:08 +0200 Subject: [PATCH 10/10] taking app name from runner --- .../main/java/com/google/adk/a2a/A2ASendMessageExecutor.java | 5 ++--- .../com/google/adk/webservice/A2ARemoteConfiguration.java | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java index 9f724e6b2..68828df94 100644 --- a/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java +++ b/a2a/google-adk-a2a-core/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java @@ -63,10 +63,9 @@ public A2ASendMessageExecutor(InMemorySessionService sessionService, String appN this.agentTimeout = null; } - public A2ASendMessageExecutor( - Runner runner, String appName, Duration agentTimeout, AgentCard agentCard) { + public A2ASendMessageExecutor(Runner runner, Duration agentTimeout, AgentCard agentCard) { this.sessionService = runner.sessionService(); - this.appName = appName; + this.appName = runner.appName(); this.runner = runner; this.agentTimeout = agentTimeout; this.agentCard = agentCard; diff --git a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java index 80a721b19..b1cd4cb17 100644 --- a/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java +++ b/a2a/google-adk-a2a-webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java @@ -50,8 +50,7 @@ public A2ASendMessageExecutor a2aSendMessageExecutor( return new A2ASendMessageExecutor( agent, appName, Duration.ofSeconds(timeoutSeconds), agentCard); } else if (runner != null) { - return new A2ASendMessageExecutor( - runner, appName, Duration.ofSeconds(timeoutSeconds), agentCard); + return new A2ASendMessageExecutor(runner, Duration.ofSeconds(timeoutSeconds), agentCard); } throw new IllegalStateException("Neither BaseAgent nor Runner is available!"); }