diff --git a/contrib/multi-agent-patterns/.gitignore b/contrib/multi-agent-patterns/.gitignore
new file mode 100644
index 000000000..776d519f4
--- /dev/null
+++ b/contrib/multi-agent-patterns/.gitignore
@@ -0,0 +1,29 @@
+# Compiled class file
+*.class
+*.classpath
+*.project
+*.settings
+*.factorypath
+target/
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+replay_pid*
diff --git a/contrib/multi-agent-patterns/README.md b/contrib/multi-agent-patterns/README.md
new file mode 100644
index 000000000..db47440e6
--- /dev/null
+++ b/contrib/multi-agent-patterns/README.md
@@ -0,0 +1,111 @@
+# Multi-Agent Patterns
+
+This repository demonstrates various multi-agent patterns using the ADK (Agent Development Kit) framework. It showcases how multiple AI agents can collaborate to perform complex tasks across different domains, including code generation, report writing, and travel planning.
+
+## Overview
+
+The project implements several key multi-agent patterns:
+
+- **Sequential Pipeline**: Agents execute in a linear sequence, passing outputs from one to the next.
+- **Coordinator/Dispatcher Pattern**: A central agent routes tasks to specialized sub-agents based on the request type.
+- **Iterative Refinement Loop**: An agent iteratively improves content based on feedback until a satisfactory result is achieved.
+- **Generator and Critic**: A generator creates initial content, and a critic reviews and provides feedback for improvement.
+- **Hierarchical Decomposition (Russian Doll)**: Agents are organized in nested layers, with higher-level agents delegating to lower-level specialized agents.
+- **Composite Patterns (Mix-and-Match)**: Combines sequential and parallel execution modes for flexible, efficient workflows.
+
+## Projects
+
+The repository includes three main projects, each illustrating different patterns:
+
+### 1. Code Workflow (`src/main/java/com/google/adk/agents/code/`)
+Demonstrates Sequential Pipeline, Coordinator/Dispatcher, Iterative Refinement Loop, and Generator and Critic patterns for code generation, conversion, and refinement.
+
+### 2. Report Writer (`src/main/java/com/google/adk/agents/report/`)
+Showcases Hierarchical Decomposition pattern for generating comprehensive reports through nested agent coordination.
+
+### 3. Trip Advisor (`src/main/java/com/google/adk/agents/traveler/`)
+Illustrates Composite Patterns with a mix of sequential and parallel agents for personalized travel itinerary planning.
+
+## Prerequisites
+
+- Java 17+
+- Maven 3+
+- **GEMINI API Key**: All agents require a valid Gemini API key for LLM operations.
+ Ensure it's configured in your environment.
+
+## Running the Project
+
+### Individual Agent
+
+Run each agent separately:
+
+**Code Workflow:**
+
+```bash
+cd contrib/multi-agent-patterns
+mvn compile exec:java -Dexec.mainClass=com.google.adk.agents.code.CodeWorkflowApp
+```
+
+**Report Writer:**
+
+```bash
+cd contrib/multi-agent-patterns
+mvn compile exec:java -Dexec.mainClass=com.google.adk.agents.report.ReportWriterApp
+```
+
+**Trip Advisor:**
+
+```bash
+cd contrib/multi-agent-patterns
+mvn compile exec:java -Dexec.mainClass=com.google.adk.agents.traveler.TravelerApp
+```
+
+### All Agents Together
+
+To run all agents simultaneously in a single web server:
+
+```bash
+cd contrib/multi-agent-patterns
+mvn compile exec:java -Dexec.mainClass=com.google.adk.agents.MultiAgentsSystem
+```
+
+Each project starts a web server where you can interact with the respective agents.
+
+## Project Structure
+
+```
+multiagent-patterns/
+├── pom.xml
+├── src/main/java/com/google/adk/agents/
+│ ├── MultiAgentsSystem.java # Runs all agents together
+│ ├── code/ # Code workflow agent
+│ │ ├── CodeWorkflowApp.java
+│ │ ├── CodeRootAgent.java
+│ │ └── ...
+│ ├── report/ # Report writer agent
+│ │ ├── ReportWriterApp.java
+│ │ ├── ReportRootAgent.java
+│ │ └── ...
+│ └── traveler/ # Trip Advisor agent
+│ ├── TravelerApp.java
+│ ├── TravelerRootAgent.java
+│ └── ...
+└── src/main/resources/agents/
+ ├── code/ # Code agent configs
+ ├── report/ # Report agent configs
+ └── traveler/ # TripAdvisor agent configs
+```
+
+## Dependencies
+
+- ADK Core
+- ADK Dev (for web UI)
+- Jackson (for YAML/JSON handling)
+- Jakarta Inject
+- Apache Commons Lang
+
+## Reference
+
+For more information on multi-agent patterns in ADK, see:
+[Developer’s guide to multi-agent patterns in ADK](https://developers.googleblog.com/developers-guide-to-multi-agent-patterns-in-adk/)
+
diff --git a/contrib/multi-agent-patterns/pom.xml b/contrib/multi-agent-patterns/pom.xml
new file mode 100644
index 000000000..c0ab74f85
--- /dev/null
+++ b/contrib/multi-agent-patterns/pom.xml
@@ -0,0 +1,66 @@
+
+
+ 4.0.0
+
+
+ com.google.adk
+ google-adk-parent
+ 1.1.1-SNAPSHOT
+ ../../pom.xml
+
+
+ multi-agent-patterns
+ Agent Development Kit - Multi-Agent Patterns
+ Multi-Agent Patterns Examples
+
+ 2.17.0
+ 2.0.1
+ 3.20.0
+
+
+
+
+ com.google.adk
+ google-adk
+ ${project.version}
+
+
+
+ com.google.adk
+ google-adk-dev
+ ${project.version}
+ compile
+
+
+
+ jakarta.inject
+ jakarta.inject-api
+
+ compile
+
+
+
+ org.apache.commons
+ commons-lang3
+
+ compile
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-guava
+
+
+
+
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/MultiAgentsSystem.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/MultiAgentsSystem.java
new file mode 100644
index 000000000..2d6d07f3d
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/MultiAgentsSystem.java
@@ -0,0 +1,27 @@
+package com.google.adk.agents;
+
+import com.google.adk.agents.base.AgentConfig;
+import com.google.adk.agents.base.AgentConfigsProvider;
+import com.google.adk.agents.code.CodeRootAgent;
+import com.google.adk.agents.report.ReportRootAgent;
+import com.google.adk.agents.traveler.TravelerRootAgent;
+import com.google.adk.web.AdkWebServer;
+import java.util.Map;
+
+/*
+ * run command:
+ * cd contrib/multi-agent-patterns
+ * mvn compile exec:java -Dexec.mainClass=com.google.adk.agents.MultiAgentsSystem
+ */
+public class MultiAgentsSystem {
+
+ public static void main(String[] agrs) {
+ AgentConfigsProvider provider = new AgentConfigsProvider();
+ Map configs = provider.get();
+ AdkWebServer.start( //
+ new CodeRootAgent(configs).get(), //
+ new ReportRootAgent(configs).get(), //
+ new TravelerRootAgent(configs).get() //
+ );
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/AgentConfig.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/AgentConfig.java
new file mode 100644
index 000000000..e714cfbba
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/AgentConfig.java
@@ -0,0 +1,228 @@
+package com.google.adk.agents.base;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Optional.empty;
+import static java.util.Optional.ofNullable;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import java.util.Optional;
+
+@JsonDeserialize(builder = AgentConfig.Builder.class)
+public final class AgentConfig {
+
+ private final String name;
+ private final String model;
+ private final String description;
+ private final String instruction;
+ private final Optional outputKey;
+ private final Optional includeContents;
+ private final Optional transferToAgent;
+ private final Optional contentConfig;
+
+ private AgentConfig(Builder builder) {
+ this.name = builder.name;
+ this.model = builder.model;
+ this.description = builder.description;
+ this.instruction = builder.instruction;
+ this.outputKey = builder.outputKey;
+ this.includeContents = builder.includeContents;
+ this.transferToAgent = builder.transferToAgent;
+ this.contentConfig = builder.contentConfig;
+ }
+
+ public static class Builder {
+ private String name;
+ private String model;
+ private String description;
+ private String instruction;
+ private Optional outputKey = empty();
+ private Optional includeContents = empty();
+ private Optional transferToAgent = empty();
+ private Optional contentConfig = empty();
+
+ public final Builder withName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public final Builder withModel(String model) {
+ this.model = model;
+ return this;
+ }
+
+ public final Builder withDescription(String description) {
+ this.description = description;
+ return this;
+ }
+
+ public final Builder withInstruction(String instruction) {
+ this.instruction = instruction;
+ return this;
+ }
+
+ public final Builder withOutputKey(Optional outputKey) {
+ this.outputKey = outputKey;
+ return this;
+ }
+
+ public final Builder withIncludeContents(Optional includeContents) {
+ this.includeContents = includeContents;
+ return this;
+ }
+
+ public final Builder withTransferToAgent(Optional transferToAgent) {
+ this.transferToAgent = transferToAgent;
+ return this;
+ }
+
+ public final Builder withContextConfig(Optional contentConfig) {
+ this.contentConfig = contentConfig;
+ return this;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getInstruction() {
+ return instruction;
+ }
+
+ public void setInstruction(String instruction) {
+ this.instruction = instruction;
+ }
+
+ public Optional getOutputKey() {
+ return outputKey;
+ }
+
+ @JsonProperty
+ public void setOutputKey(String outputKey) {
+ setOutputKey(ofNullable(outputKey));
+ }
+
+ public void setOutputKey(Optional outputKey) {
+ this.outputKey = outputKey;
+ }
+
+ public Optional getIncludeContents() {
+ return includeContents;
+ }
+
+ @JsonProperty
+ public void setIncludeContents(String includeContents) {
+ setIncludeContents(ofNullable(includeContents));
+ }
+
+ public void setIncludeContents(Optional includeContents) {
+ this.includeContents = includeContents;
+ }
+
+ public Optional getTransferToAgent() {
+ return transferToAgent;
+ }
+
+ @JsonProperty
+ public void setTransferToAgent(String transferToAgent) {
+ setTransferToAgent(ofNullable(transferToAgent));
+ }
+
+ public void setTransferToAgent(Optional transferToAgent) {
+ this.transferToAgent = transferToAgent;
+ }
+
+ public Optional getContentConfig() {
+ return contentConfig;
+ }
+
+ @JsonProperty
+ public void setContentConfig(ContentConfig contentConfig) {
+ setContentConfig(ofNullable(contentConfig));
+ }
+
+ public void setContentConfig(Optional contentConfig) {
+ this.contentConfig = contentConfig;
+ }
+
+ public AgentConfig build() {
+ return validate(new AgentConfig(this));
+ }
+
+ private static AgentConfig validate(AgentConfig instance) {
+ checkNotNull(instance.name);
+ checkNotNull(instance.model);
+ checkNotNull(instance.description);
+ checkNotNull(instance.instruction);
+ return instance;
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getInstruction() {
+ return instruction;
+ }
+
+ public Optional getOutputKey() {
+ return outputKey;
+ }
+
+ public Optional getIncludeContents() {
+ return includeContents;
+ }
+
+ public Optional getTransferToAgent() {
+ return transferToAgent;
+ }
+
+ public Optional getContentConfig() {
+ return contentConfig;
+ }
+
+ @Override
+ public String toString() {
+ ToStringHelper helper = toStringHelper(this);
+ helper.add("name", name);
+ helper.add("model", model);
+ helper.add("description", description);
+ helper.add("instruction", instruction);
+ helper.add("outputKey", outputKey);
+ helper.add("includeContents", includeContents);
+ helper.add("transferToAgent", transferToAgent);
+ helper.add("contentConfig", contentConfig);
+ return helper.toString();
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/AgentConfigsProvider.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/AgentConfigsProvider.java
new file mode 100644
index 000000000..9aee47a31
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/AgentConfigsProvider.java
@@ -0,0 +1,87 @@
+package com.google.adk.agents.base;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.and;
+import static com.google.common.reflect.ClassPath.from;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.adk.agents.base.serialize.YamlSerializer;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.ByteSource;
+import com.google.common.reflect.ClassPath;
+import com.google.common.reflect.ClassPath.ResourceInfo;
+import jakarta.inject.Provider;
+import java.io.IOException;
+import java.util.Map;
+import java.util.regex.Pattern;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AgentConfigsProvider implements Provider> {
+
+ private static final String CONFIG = "agent-configs";
+ private static final String EXT = ".yaml";
+
+ private static final Logger log = LoggerFactory.getLogger(AgentConfigsProvider.class);
+
+ public AgentConfigsProvider() {
+ this(new YamlSerializer());
+ }
+
+ public AgentConfigsProvider(YamlSerializer yaml) {
+ this.yaml = checkNotNull(yaml, "yaml");
+ }
+
+ private final YamlSerializer yaml;
+
+ @Override
+ public ImmutableMap get() {
+ try {
+ Map resources = classpathResources(CONFIG);
+ ImmutableMap.Builder builder = ImmutableMap.builder();
+ for (Map.Entry entry : resources.entrySet()) {
+ AgentConfig config = yaml.read(entry.getValue(), AgentConfig.class);
+ builder.put(normalize(entry.getKey(), CONFIG), config);
+ }
+ ImmutableMap map = builder.build();
+ String msg = "Loaded agent configurations [total = %s] from classpath directory -> %s";
+ log.info(String.format(msg, map.size(), CONFIG));
+ return map;
+ } catch (JsonProcessingException e) { // Specific for YAML parsing errors
+ throw new IllegalStateException("Failed to parse agent configuration YAML", e);
+ } catch (IOException e) { // For other I/O errors
+ throw new IllegalStateException("Failed to load agent configurations from classpath", e);
+ } catch (Exception e) { // Catch broader exceptions, but not Throwable
+ String msg = "An unexpected error occurred while loading agent configurations";
+ throw new IllegalStateException(msg, e);
+ }
+ }
+
+ private ImmutableMap classpathResources(String dir) throws IOException {
+ ClassPath classPath = from(getClass().getClassLoader());
+ ImmutableMap.Builder builder = ImmutableMap.builder();
+ Predicate filter = pathPredicate(dir);
+ for (ResourceInfo info : classPath.getResources()) {
+ if (filter.apply(info)) {
+ builder.put(info.getResourceName(), info.asByteSource());
+ }
+ }
+ return builder.build();
+ }
+
+ private Predicate pathPredicate(String dir) {
+ String prefix = dir.endsWith("/") ? dir : dir + "/";
+ Predicate startsWith = p -> p.getResourceName().startsWith(prefix);
+ Predicate endsWith = p -> p.getResourceName().endsWith(EXT);
+ return and(startsWith, endsWith);
+ }
+
+ private String normalize(String s, String dir) {
+ return s.replaceFirst("^" + Pattern.quote(dir + "/"), "")
+ .replaceFirst(Pattern.quote(EXT) + "$", "")
+ .replace("-", ".")
+ .replace("_", ".")
+ .replace("/", ".");
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/AgentContext.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/AgentContext.java
new file mode 100644
index 000000000..dc5b2d778
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/AgentContext.java
@@ -0,0 +1,83 @@
+package com.google.adk.agents.base;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableList.copyOf;
+import static java.util.Arrays.asList;
+
+import com.google.adk.agents.BaseAgent;
+import com.google.adk.tools.BaseTool;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class AgentContext {
+
+ private final AgentConfig config;
+ private final ImmutableList extends BaseTool> tools;
+ private final ImmutableList extends BaseAgent> subAgents;
+
+ public static AgentContext build(AgentConfig config) {
+ return builder().withConfig(config).build();
+ }
+
+ public static AgentContext build(AgentConfig config, BaseTool base) {
+ return builder().withConfig(config).withTools(base).build();
+ }
+
+ public static final Builder builder() {
+ return new Builder();
+ }
+
+ private AgentContext(Builder builder) {
+ this.config = builder.config;
+ this.tools = copyOf(builder.tools);
+ this.subAgents = copyOf(builder.subAgents);
+ }
+
+ public static class Builder {
+
+ private AgentConfig config;
+ private List extends BaseTool> tools = new ArrayList<>();
+ private List extends BaseAgent> subAgents = new ArrayList<>();
+
+ public final Builder withConfig(AgentConfig config) {
+ this.config = config;
+ return this;
+ }
+
+ public final Builder withTools(BaseTool... tools) {
+ return withTools(asList(tools));
+ }
+
+ public final Builder withTools(List extends BaseTool> tools) {
+ this.tools = tools;
+ return this;
+ }
+
+ public final Builder withSubAgents(List extends BaseAgent> subAgents) {
+ this.subAgents = subAgents;
+ return this;
+ }
+
+ public AgentContext build() {
+ return validate(new AgentContext(this));
+ }
+
+ private static AgentContext validate(AgentContext instance) {
+ checkNotNull(instance.getConfig());
+ return instance;
+ }
+ }
+
+ public AgentConfig getConfig() {
+ return config;
+ }
+
+ public ImmutableList extends BaseTool> getTools() {
+ return tools;
+ }
+
+ public ImmutableList extends BaseAgent> getSubAgents() {
+ return subAgents;
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/ContentConfig.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/ContentConfig.java
new file mode 100644
index 000000000..f79689a16
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/ContentConfig.java
@@ -0,0 +1,95 @@
+package com.google.adk.agents.base;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Optional.empty;
+import static java.util.Optional.ofNullable;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import java.util.Optional;
+
+@JsonDeserialize(builder = ContentConfig.Builder.class)
+public final class ContentConfig {
+
+ private final Optional temperature;
+ private final Optional maxOutputTokens;
+
+ private ContentConfig(Builder builder) {
+ this.temperature = builder.temperature;
+ this.maxOutputTokens = builder.maxOutputTokens;
+ }
+
+ public static class Builder {
+ private Optional temperature = empty();
+ private Optional maxOutputTokens = empty();
+
+ public final Builder withTemperature(Optional temperature) {
+ this.temperature = temperature;
+ return this;
+ }
+
+ public final Builder withMaxOutputTokens(Optional maxOutputTokens) {
+ this.maxOutputTokens = maxOutputTokens;
+ return this;
+ }
+
+ public Optional getTemperature() {
+ return temperature;
+ }
+
+ public Optional getMaxOutputTokens() {
+ return maxOutputTokens;
+ }
+
+ @JsonProperty
+ public void setTemperature(float temperature) {
+ setTemperature(ofNullable(temperature));
+ }
+
+ public void setTemperature(Optional temperature) {
+ this.temperature = temperature;
+ }
+
+ @JsonProperty
+ public void setMaxOutputTokens(int maxOutputTokens) {
+ setMaxOutputTokens(ofNullable(maxOutputTokens));
+ }
+
+ public void setMaxOutputTokens(Optional maxOutputTokens) {
+ this.maxOutputTokens = maxOutputTokens;
+ }
+
+ public ContentConfig build() {
+ return validate(new ContentConfig(this));
+ }
+
+ private static ContentConfig validate(ContentConfig instance) {
+ if (instance.temperature.isPresent()) {
+ checkArgument(instance.temperature.get() > 0.0, "positive temperature expected");
+ }
+ if (instance.maxOutputTokens.isPresent()) {
+ checkArgument(
+ instance.maxOutputTokens.get() > 0, "maxOutput tokens can't be zero or negative");
+ }
+ return instance;
+ }
+ }
+
+ public Optional getTemperature() {
+ return temperature;
+ }
+
+ public Optional getMaxOutputTokens() {
+ return maxOutputTokens;
+ }
+
+ @Override
+ public String toString() {
+ ToStringHelper helper = toStringHelper(this);
+ helper.add("temperature", temperature);
+ helper.add("maxOutputTokens", maxOutputTokens);
+ return helper.toString();
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/DefaultContentConfigProvider.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/DefaultContentConfigProvider.java
new file mode 100644
index 000000000..e71604c7d
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/DefaultContentConfigProvider.java
@@ -0,0 +1,47 @@
+package com.google.adk.agents.base;
+
+import static com.google.common.collect.ImmutableList.of;
+
+import com.google.common.collect.ImmutableList;
+import com.google.genai.types.GenerateContentConfig;
+import com.google.genai.types.HttpOptions;
+import com.google.genai.types.HttpRetryOptions;
+import jakarta.inject.Provider;
+
+// https://adk.dev/agents/models/google-gemini/#error-code-429-resource_exhausted
+
+public class DefaultContentConfigProvider implements Provider {
+
+ private static final int MAX_RETRY = 3;
+ private static final int MAX_TOKENS = 2000;
+ private static final double TEMP = 0.1;
+ private static final double JITTER = 1.0;
+ private static final double INITIAL_DELAY = 1.0;
+ private static final double DELAY_MULTIPLIER = 15.0;
+ private static final ImmutableList STATUS_CODES = of(429, 500, 503, 504);
+
+ @Override
+ public GenerateContentConfig get() {
+ return GenerateContentConfig.builder() //
+ .temperature(Double.valueOf(TEMP).floatValue()) //
+ .maxOutputTokens(MAX_TOKENS) //
+ .httpOptions(httpOptions()) //
+ .build();
+ }
+
+ private HttpOptions httpOptions() {
+ return HttpOptions.builder() //
+ .retryOptions(retryOptions()) //
+ .build(); //
+ }
+
+ private HttpRetryOptions retryOptions() {
+ return HttpRetryOptions.builder()
+ .initialDelay(INITIAL_DELAY) //
+ .expBase(DELAY_MULTIPLIER) // delay multiplier
+ .attempts(MAX_RETRY) // max retry attempts
+ .jitter(JITTER) //
+ .httpStatusCodes(STATUS_CODES) // retry on these HTTP errors
+ .build(); //
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/LlmAgentProvider.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/LlmAgentProvider.java
new file mode 100644
index 000000000..925685f7a
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/LlmAgentProvider.java
@@ -0,0 +1,72 @@
+package com.google.adk.agents.base;
+
+import static com.google.adk.agents.LlmAgent.IncludeContents.DEFAULT;
+import static com.google.adk.agents.LlmAgent.IncludeContents.valueOf;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.adk.agents.LlmAgent;
+import com.google.common.base.CharMatcher;
+import com.google.genai.types.GenerateContentConfig;
+import io.reactivex.rxjava3.core.Maybe;
+import jakarta.inject.Provider;
+import java.util.Optional;
+
+public class LlmAgentProvider implements Provider {
+
+ public LlmAgentProvider(AgentConfig config) {
+ this(AgentContext.build(config));
+ }
+
+ public LlmAgentProvider(AgentContext ctx) {
+ this.ctx = checkNotNull(ctx, "ctx");
+ }
+
+ private final AgentContext ctx;
+
+ @Override
+ public LlmAgent get() {
+ AgentConfig config = ctx.getConfig();
+ LlmAgent.Builder builder = LlmAgent.builder();
+ builder.name(config.getName());
+ builder.description(config.getDescription());
+ builder.model(config.getModel());
+ builder.instruction(config.getInstruction());
+ builder.includeContents(includeContents(config));
+ if (config.getOutputKey().isPresent()) {
+ builder.outputKey(config.getOutputKey().get());
+ }
+ if (config.getTransferToAgent().isPresent()) {
+ String name = config.getTransferToAgent().get();
+ builder.afterAgentCallback(
+ cc -> {
+ cc.eventActions().setTransferToAgent(name);
+ return Maybe.empty();
+ });
+ }
+ builder.tools(ctx.getTools());
+ builder.subAgents(ctx.getSubAgents());
+ builder.generateContentConfig(contentConfig(config.getContentConfig()));
+ return builder.build();
+ }
+
+ private GenerateContentConfig contentConfig(Optional content) {
+ GenerateContentConfig gcc = new DefaultContentConfigProvider().get();
+ if (!content.isPresent()) {
+ return gcc;
+ }
+ ContentConfig cc = content.get();
+ return GenerateContentConfig.builder() //
+ .temperature(cc.getTemperature().orElse(gcc.temperature().get())) //
+ .maxOutputTokens(cc.getMaxOutputTokens().orElse(gcc.maxOutputTokens().get())) //
+ .build();
+ }
+
+ private LlmAgent.IncludeContents includeContents(AgentConfig config) {
+ Optional incl = config.getIncludeContents();
+ if (incl.isPresent()) {
+ String trimmed = CharMatcher.whitespace().trimFrom(incl.get());
+ return valueOf(trimmed.toUpperCase());
+ }
+ return DEFAULT;
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/serialize/YamlMapperProvider.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/serialize/YamlMapperProvider.java
new file mode 100644
index 000000000..71f72bfcb
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/serialize/YamlMapperProvider.java
@@ -0,0 +1,22 @@
+package com.google.adk.agents.base.serialize;
+
+import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.MINIMIZE_QUOTES;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import jakarta.inject.Provider;
+
+public final class YamlMapperProvider implements Provider {
+
+ @Override
+ public ObjectMapper get() {
+ YAMLFactory factory = new YAMLFactory().enable(MINIMIZE_QUOTES);
+ ObjectMapper mapper = new ObjectMapper(factory);
+ // mapper.registerModule(new GuavaModule());
+ mapper.registerModule(new Jdk8Module());
+ mapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_EMPTY);
+ return mapper;
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/serialize/YamlSerializer.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/serialize/YamlSerializer.java
new file mode 100644
index 000000000..0612d67b7
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/serialize/YamlSerializer.java
@@ -0,0 +1,41 @@
+package com.google.adk.agents.base.serialize;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.io.ByteSource;
+import java.io.IOException;
+import java.io.InputStream;
+
+public final class YamlSerializer {
+
+ public YamlSerializer() {
+ this(new YamlMapperProvider().get());
+ }
+
+ public YamlSerializer(ObjectMapper mapper) {
+ this.mapper = mapper.copy();
+ }
+
+ private final ObjectMapper mapper;
+
+ public T read(InputStream in, Class type) throws IOException {
+ checkNotNull(in, "in");
+ checkNotNull(type, "type");
+ return mapper.readValue(in, type);
+ }
+
+ public T read(ByteSource source, Class type) throws IOException {
+ checkNotNull(source, "source");
+ checkNotNull(type, "type");
+ try (InputStream in = source.openBufferedStream()) {
+ return read(in, type);
+ } catch (Throwable e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public ObjectMapper getMapper() {
+ return mapper.copy();
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/tools/CodeExecutionToolProvider.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/tools/CodeExecutionToolProvider.java
new file mode 100644
index 000000000..cb954a7af
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/tools/CodeExecutionToolProvider.java
@@ -0,0 +1,33 @@
+package com.google.adk.agents.base.tools;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableMap.copyOf;
+
+import com.google.adk.agents.LlmAgent;
+import com.google.adk.agents.base.AgentConfig;
+import com.google.adk.agents.base.AgentContext;
+import com.google.adk.agents.base.LlmAgentProvider;
+import com.google.adk.tools.AgentTool;
+import com.google.adk.tools.BuiltInCodeExecutionTool;
+import com.google.common.collect.ImmutableMap;
+import jakarta.inject.Provider;
+import java.util.Map;
+
+public class CodeExecutionToolProvider implements Provider {
+
+ private static final String KEY = "tool.code.execution";
+
+ public CodeExecutionToolProvider(Map configs) {
+ this.configs = copyOf(checkNotNull(configs, "configs"));
+ }
+
+ private final ImmutableMap configs;
+
+ @Override
+ public AgentTool get() {
+ BuiltInCodeExecutionTool tool = new BuiltInCodeExecutionTool();
+ AgentContext ctx = AgentContext.build(configs.get(KEY), tool);
+ LlmAgent agent = new LlmAgentProvider(ctx).get();
+ return AgentTool.create(agent);
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/tools/MapsAgentToolProvider.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/tools/MapsAgentToolProvider.java
new file mode 100644
index 000000000..a9ce379d0
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/tools/MapsAgentToolProvider.java
@@ -0,0 +1,33 @@
+package com.google.adk.agents.base.tools;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableMap.copyOf;
+
+import com.google.adk.agents.LlmAgent;
+import com.google.adk.agents.base.AgentConfig;
+import com.google.adk.agents.base.AgentContext;
+import com.google.adk.agents.base.LlmAgentProvider;
+import com.google.adk.tools.AgentTool;
+import com.google.adk.tools.GoogleMapsTool;
+import com.google.common.collect.ImmutableMap;
+import jakarta.inject.Provider;
+import java.util.Map;
+
+public class MapsAgentToolProvider implements Provider {
+
+ private static final String KEY = "tool.maps.agent";
+
+ public MapsAgentToolProvider(Map configs) {
+ this.configs = copyOf(checkNotNull(configs, "configs"));
+ }
+
+ private final ImmutableMap configs;
+
+ @Override
+ public AgentTool get() {
+ GoogleMapsTool tool = new GoogleMapsTool();
+ AgentContext ctx = AgentContext.build(configs.get(KEY), tool);
+ LlmAgent agent = new LlmAgentProvider(ctx).get();
+ return AgentTool.create(agent);
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/tools/SearchAgentToolProvider.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/tools/SearchAgentToolProvider.java
new file mode 100644
index 000000000..a09f3da9e
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/base/tools/SearchAgentToolProvider.java
@@ -0,0 +1,33 @@
+package com.google.adk.agents.base.tools;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableMap.copyOf;
+
+import com.google.adk.agents.LlmAgent;
+import com.google.adk.agents.base.AgentConfig;
+import com.google.adk.agents.base.AgentContext;
+import com.google.adk.agents.base.LlmAgentProvider;
+import com.google.adk.tools.AgentTool;
+import com.google.adk.tools.GoogleSearchTool;
+import com.google.common.collect.ImmutableMap;
+import jakarta.inject.Provider;
+import java.util.Map;
+
+public class SearchAgentToolProvider implements Provider {
+
+ private static final String KEY = "tool.search.agent";
+
+ public SearchAgentToolProvider(Map configs) {
+ this.configs = copyOf(checkNotNull(configs, "configs"));
+ }
+
+ private final ImmutableMap configs;
+
+ @Override
+ public AgentTool get() {
+ GoogleSearchTool tool = new GoogleSearchTool();
+ AgentContext ctx = AgentContext.build(configs.get(KEY), tool);
+ LlmAgent agent = new LlmAgentProvider(ctx).get();
+ return AgentTool.create(agent);
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/CodeRefinementLoop.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/CodeRefinementLoop.java
new file mode 100644
index 000000000..8f69fae93
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/CodeRefinementLoop.java
@@ -0,0 +1,58 @@
+package com.google.adk.agents.code;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableMap.copyOf;
+
+import com.google.adk.agents.LlmAgent;
+import com.google.adk.agents.LoopAgent;
+import com.google.adk.agents.base.AgentConfig;
+import com.google.adk.agents.base.AgentContext;
+import com.google.adk.agents.base.LlmAgentProvider;
+import com.google.adk.tools.AgentTool;
+import com.google.adk.tools.BaseTool;
+import com.google.adk.tools.ExitLoopTool;
+import com.google.common.collect.ImmutableMap;
+import jakarta.inject.Provider;
+import java.util.Map;
+
+public class CodeRefinementLoop implements Provider {
+
+ private static final int MAX_ITER = 3;
+ private static final String CRA_KEY = "code.review.agent";
+ private static final String CFA_KEY = "code.refiner.agent";
+
+ private static final String DESC =
+ """
+ Improves code performance based on review feedback or signals completion.
+ """;
+
+ public CodeRefinementLoop(AgentTool execTool, Map configs) {
+ this.execTool = checkNotNull(execTool);
+ this.configs = copyOf(configs);
+ }
+
+ private final AgentTool execTool;
+ private final ImmutableMap configs;
+
+ @Override
+ public LoopAgent get() {
+ LlmAgent review = llmAgent(CRA_KEY, execTool);
+ LlmAgent refiner = llmAgent(CFA_KEY, execTool, ExitLoopTool.INSTANCE);
+ return LoopAgent.builder() //
+ .name("CodeRefinementLoop") //
+ .description(DESC) //
+ .subAgents(review, refiner) //
+ .maxIterations(MAX_ITER) //
+ .build();
+ }
+
+ private LlmAgent llmAgent(String key, BaseTool... tools) {
+ AgentConfig config = configs.get(key);
+ AgentContext ctx =
+ AgentContext.builder() //
+ .withConfig(config) //
+ .withTools(tools) //
+ .build();
+ return new LlmAgentProvider(ctx).get();
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/CodeRootAgent.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/CodeRootAgent.java
new file mode 100644
index 000000000..c496c4b70
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/CodeRootAgent.java
@@ -0,0 +1,80 @@
+package com.google.adk.agents.code;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableMap.copyOf;
+
+import com.google.adk.agents.LlmAgent;
+import com.google.adk.agents.LoopAgent;
+import com.google.adk.agents.SequentialAgent;
+import com.google.adk.agents.base.AgentConfig;
+import com.google.adk.agents.base.AgentContext;
+import com.google.adk.agents.base.LlmAgentProvider;
+import com.google.adk.agents.base.tools.CodeExecutionToolProvider;
+import com.google.adk.tools.AgentTool;
+import com.google.common.collect.ImmutableMap;
+import jakarta.inject.Provider;
+import java.util.Map;
+
+public class CodeRootAgent implements Provider {
+
+ private static final String CRA_KEY = "code.root.agent";
+ private static final String CGA_KEY = "code.generator.agent";
+ private static final String CTA_KEY = "code.converter.agent";
+ private static final String CCA_KEY = "code.critic.agent";
+ private static final String CFA_KEY = "code.refactor.agent";
+ private static final String CBA_KEY = "code.bundler.agent";
+
+ public CodeRootAgent(Map configs) {
+ this.configs = copyOf(checkNotNull(configs, "configs"));
+ }
+
+ private final ImmutableMap configs;
+
+ @Override
+ public LlmAgent get() {
+ AgentTool generator = AgentTool.create(generationWorkflow(configs));
+ AgentTool converter = AgentTool.create(conversionWorkflow(configs));
+ AgentTool fullLoop = AgentTool.create(fullLoop(configs));
+ AgentContext ctx =
+ AgentContext.builder() //
+ .withConfig(configs.get(CRA_KEY)) //
+ .withTools(generator, converter, fullLoop) //
+ .build(); //
+ return new LlmAgentProvider(ctx).get();
+ }
+
+ private SequentialAgent fullLoop(Map configs) {
+ SequentialAgent generator = generationWorkflow(configs);
+ SequentialAgent converter = conversionWorkflow(configs);
+ LlmAgent bundler = new LlmAgentProvider(AgentContext.build(configs.get(CBA_KEY))).get();
+ return SequentialAgent.builder() //
+ .name("FullLoopWorkflow") //
+ .description("Generates and converts code") //
+ .subAgents(generator, converter, bundler) //
+ .build();
+ }
+
+ private SequentialAgent conversionWorkflow(Map configs) {
+ AgentTool tool = new CodeExecutionToolProvider(configs).get();
+ LlmAgent convert = new LlmAgentProvider(AgentContext.build(configs.get(CTA_KEY), tool)).get();
+ LlmAgent review = new LlmAgentProvider(AgentContext.build(configs.get(CCA_KEY), tool)).get();
+ LlmAgent refactor = new LlmAgentProvider(AgentContext.build(configs.get(CFA_KEY), tool)).get();
+ return SequentialAgent.builder() //
+ .name("CodeConversionWorkflow") //
+ .description("Converts code with review-refactor") //
+ .subAgents(convert, review, refactor) //
+ .build();
+ }
+
+ private SequentialAgent generationWorkflow(Map configs) {
+ AgentTool tool = new CodeExecutionToolProvider(configs).get();
+ AgentContext ctx = AgentContext.build(configs.get(CGA_KEY), tool);
+ LlmAgent generator = new LlmAgentProvider(ctx).get();
+ LoopAgent refiner = new CodeRefinementLoop(tool, configs).get();
+ return SequentialAgent.builder() //
+ .name("CodeGenerationWorkflow") //
+ .description("Generates code with Refinement Loop") //
+ .subAgents(generator, refiner) //
+ .build();
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/CodeWorkflowApp.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/CodeWorkflowApp.java
new file mode 100644
index 000000000..cb5b30a73
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/CodeWorkflowApp.java
@@ -0,0 +1,19 @@
+package com.google.adk.agents.code;
+
+import com.google.adk.agents.base.AgentConfigsProvider;
+import com.google.adk.web.AdkWebServer;
+
+/*
+ * run command:
+ * cd contrib/multi-agent-patterns
+ * mvn compile exec:java -Dexec.mainClass=com.google.adk.agents.code.CodeWorkflowApp
+ */
+
+public final class CodeWorkflowApp {
+
+ public static void main(String[] agrs) {
+ AgentConfigsProvider configs = new AgentConfigsProvider();
+ CodeRootAgent root = new CodeRootAgent(configs.get());
+ AdkWebServer.start(root.get());
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/README.md b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/README.md
new file mode 100644
index 000000000..5fb455fdc
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/code/README.md
@@ -0,0 +1,110 @@
+# Code Workflow
+
+This project demonstrates various multi-agent patterns using the ADK (Agent Development Kit) framework. It showcases how multiple AI agents can collaborate to perform complex tasks such as code generation, conversion, and refinement.
+
+## Overview
+
+The system implements a code workflow where agents handle different aspects of software development tasks. The main patterns demonstrated are:
+
+- **Sequential Pipeline**: Agents execute in a linear sequence, passing outputs from one to the next.
+- **Coordinator/Dispatcher Pattern**: A central agent routes tasks to specialized sub-agents based on the request type.
+- **Iterative Refinement Loop**: An agent iteratively improves code based on feedback until a satisfactory result is achieved.
+- **Generator and Critic**: A generator creates initial content, and a critic reviews and provides feedback for improvement.
+
+## How It Works
+
+The multi-agent system operates through a series of coordinated workflows, each leveraging specific patterns to achieve high-quality code outputs.
+
+### 1. Request Routing (Coordinator/Dispatcher Pattern)
+- The **CodeRootAgent** analyzes the user's request.
+- Based on the task type (generation, conversion, or both), it dispatches to the appropriate workflow.
+
+### 2. Code Generation Workflow (Sequential Pipeline + Iterative Refinement Loop)
+- **Generator Agent**: Produces initial code from problem statements.
+- **Iterative Refinement Loop** (max 3 iterations):
+ - **Review Agent**: Evaluates code for correctness, efficiency, and best practices.
+ - **Refiner Agent**: Applies improvements based on review feedback.
+ - Loop continues until code is approved or max iterations reached.
+
+### 3. Code Conversion Workflow (Sequential Pipeline + Generator and Critic)
+- **Converter Agent**: Translates code between programming languages.
+- **Critic Agent**: Reviews converted code for accuracy and style.
+- **Refactor Agent**: Refines the converted code based on critic feedback.
+
+### 4. Full Loop Workflow (Sequential Pipeline)
+- Combines generation and conversion workflows.
+- **Bundler Agent**: Synthesizes all outputs into a unified, formatted report.
+
+## Flow Diagram
+
+```
+User Input
+ ↓
+CodeRootAgent (Coordinator/Dispatcher)
+ ↓
+{Request Type}
+├─→ CodeGenerationWorkflow (Sequential Pipeline)
+│ ├─→ Generator Agent
+│ └─→ Refinement Loop (Iterative Refinement Loop)
+│ ├─→ Review Agent
+│ └─→ Refiner Agent
+├─→ CodeConversionWorkflow (Sequential Pipeline)
+│ ├─→ Converter Agent
+│ ├─→ Critic Agent (Generator and Critic)
+│ └─→ Refactor Agent
+└─→ FullLoopWorkflow (Sequential Pipeline)
+ ├─→ CodeGenerationWorkflow
+ │ ├─→ Generator Agent
+ │ └─→ Refinement Loop
+ │ ├─→ Review Agent
+ │ └─→ Refiner Agent
+ ├─→ CodeConversionWorkflow
+ │ ├─→ Converter Agent
+ │ ├─→ Critic Agent
+ │ └─→ Refactor Agent
+ └─→ Bundler Agent
+ ↓
+Code Output
+```
+
+## Agents
+
+- **CodeRootAgent**: Central dispatcher
+- **CodeGeneratorAgent**: Generates code from problem statements
+- **CodeReviewerAgent**: Reviews generated code
+- **CodeRefinerAgent**: Refines code based on feedback
+- **CodeConverterAgent**: Translates code between languages
+- **CodeCriticAgent**: Reviews converted code
+- **CodeBundlerAgent**: Combines outputs into a report
+
+## Running the Project
+
+1. Ensure you have Maven installed.
+2. Navigate to the project directory.
+3. Compile and run:
+
+```bash
+cd contrib/multi-agent-patterns
+mvn compile exec:java -Dexec.mainClass=com.google.adk.agents.code.CodeWorkflowApp
+```
+
+The application starts a web server where you can interact with the agents.
+
+## Dependencies
+
+- ADK Core
+- ADK Dev (for web UI)
+- Jackson (for YAML/JSON handling)
+- Jakarta Inject
+- Apache Commons Lang
+
+## Configuration
+
+Agent configurations are defined in YAML files under `src/main/resources/agents/code/`:
+- `root-agent.yaml`
+- `generator-agent.yaml`
+- `review-agent.yaml`
+- `refiner-agent.yaml`
+- `converter-agent.yaml`
+- `critic-agent.yaml`
+- `bundler-agent.yaml`
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/report/README.md b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/report/README.md
new file mode 100644
index 000000000..e3c439529
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/report/README.md
@@ -0,0 +1,76 @@
+# Report Writer
+
+This project demonstrates the **Hierarchical Decomposition** multi-agent pattern (also known as the "Russian Doll" pattern) using the ADK (Agent Development Kit) framework. In this pattern, agents are organized in a nested hierarchy where higher-level agents delegate tasks to lower-level agents, each responsible for specific subtasks.
+
+## Overview
+
+The Hierarchical Decomposition pattern breaks down complex tasks into smaller, manageable subtasks handled by specialized agents. This creates a layered architecture where:
+
+- **Top-level agents** coordinate and delegate work
+- **Mid-level agents** manage subteams or workflows
+- **Bottom-level agents** perform specific operations
+
+In this demo, the system generates comprehensive reports on user-specified topics by decomposing the task into research and writing phases.
+
+## How It Works
+
+The report writing process follows a hierarchical structure:
+
+1. **Report Writer Agent** (Top Level): Receives the user request and orchestrates the overall process.
+2. **Research Coordinator Agent** (Mid Level): Manages the research phase with two sub-agents.
+3. **Topic Researcher Agent** (Bottom Level): Performs web searches to gather information.
+4. **Content Analyst Agent** (Bottom Level): Analyzes and summarizes the research findings.
+
+## Flow Diagram
+
+```
+User Input
+ ↓
+ReportWriterAgent (Hierarchical Decomposition)
+ ↓
+ResearchCoordinatorAgent (Coordinator)
+ ├─→ TopicResearcherAgent (with Google Search Tool)
+ └─→ ContentAnalystAgent
+ ↓
+Final Report Output
+```
+
+## Agents
+
+- **ReportWriterAgent**: Main orchestrator that delegates research tasks and compiles the final report.
+- **ResearchCoordinatorAgent**: Coordinates research activities, managing the TopicResearcher and ContentAnalyst agents.
+- **TopicResearcherAgent**: Uses web search tools to gather relevant information on the topic.
+- **ContentAnalystAgent**: Analyzes research data and creates concise summaries.
+
+## Running the Project
+
+1. Ensure you have Maven installed.
+2. Navigate to the project directory.
+3. Compile and run:
+
+```bash
+cd contrib/multi-agent-patterns
+mvn compile exec:java -Dexec.mainClass=com.google.adk.agents.report.ReportWriterApp
+```
+
+The application starts a web server where you can interact with the agents.
+
+## Example Usage
+
+Try prompts like:
+- "Write a report on artificial intelligence"
+- "Create a report on self-driving vehicles"
+
+## Configuration
+
+Agent configurations are defined in YAML files under `src/main/resources/agents/report/`:
+- `root-writer.yaml`: Report Writer Agent configuration
+- `research-coordinator.yaml`: Research Coordinator Agent configuration
+- `topic-researcher.yaml`: Topic Researcher Agent configuration
+- `content-analyst.yaml`: Content Analyst Agent configuration
+
+## Dependencies
+
+- ADK Core
+- ADK Dev (for web UI)
+- Search tools for web research
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/report/ReportRootAgent.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/report/ReportRootAgent.java
new file mode 100644
index 000000000..2be991c17
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/report/ReportRootAgent.java
@@ -0,0 +1,59 @@
+package com.google.adk.agents.report;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableMap.copyOf;
+
+import com.google.adk.agents.LlmAgent;
+import com.google.adk.agents.base.AgentConfig;
+import com.google.adk.agents.base.AgentContext;
+import com.google.adk.agents.base.LlmAgentProvider;
+import com.google.adk.agents.base.tools.SearchAgentToolProvider;
+import com.google.adk.tools.AgentTool;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import jakarta.inject.Provider;
+import java.util.Map;
+
+public class ReportRootAgent implements Provider {
+
+ private static final String RRW_KEY = "report.root.writer";
+ private static final String RTR_KEY = "report.topic.researcher";
+ private static final String RCA_KEY = "report.content.analyst";
+ private static final String RAA_KEY = "report.research.coordinator";
+
+ public ReportRootAgent(Map configs) {
+ this.configs = copyOf(checkNotNull(configs, "configs"));
+ }
+
+ private final ImmutableMap configs;
+
+ @Override
+ public LlmAgent get() {
+ AgentTool assistant = AgentTool.create(researchAssistant(configs));
+ AgentContext ctx = AgentContext.build(configs.get(RRW_KEY), assistant);
+ return new LlmAgentProvider(ctx).get();
+ }
+
+ private LlmAgent researchAssistant(Map configs) {
+ LlmAgent search = webSearch(configs);
+ LlmAgent analyst = summarizer(configs);
+ AgentConfig config = configs.get(RAA_KEY);
+ AgentContext ctx =
+ AgentContext.builder() //
+ .withConfig(config) //
+ .withSubAgents(ImmutableList.of(search, analyst)) //
+ .build();
+ return new LlmAgentProvider(ctx).get();
+ }
+
+ private LlmAgent summarizer(Map configs) {
+ AgentContext ctx = AgentContext.build(configs.get(RCA_KEY));
+ return new LlmAgentProvider(ctx).get();
+ }
+
+ private LlmAgent webSearch(Map configs) {
+ AgentTool search = new SearchAgentToolProvider(configs).get();
+ AgentContext ctx = AgentContext.build(configs.get(RTR_KEY), search);
+ return new LlmAgentProvider(ctx).get();
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/report/ReportWriterApp.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/report/ReportWriterApp.java
new file mode 100644
index 000000000..8de82843d
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/report/ReportWriterApp.java
@@ -0,0 +1,19 @@
+package com.google.adk.agents.report;
+
+import com.google.adk.agents.base.AgentConfigsProvider;
+import com.google.adk.web.AdkWebServer;
+
+/*
+ * run command:
+ * cd contrib/multi-agent-patterns
+ * mvn compile exec:java -Dexec.mainClass=com.google.adk.agents.report.ReportWriterApp
+ */
+
+public final class ReportWriterApp {
+
+ public static void main(String[] agrs) {
+ AgentConfigsProvider configs = new AgentConfigsProvider();
+ ReportRootAgent root = new ReportRootAgent(configs.get());
+ AdkWebServer.start(root.get());
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/README.md b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/README.md
new file mode 100644
index 000000000..6ea03a1eb
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/README.md
@@ -0,0 +1,80 @@
+# Trip Advisor
+
+This project demonstrates **Composite Patterns** (mix-and-match of sequential and parallel agents) using the ADK (Agent Development Kit) framework. Composite patterns combine different agent orchestration strategies—such as sequential pipelines and parallel execution—to create flexible, efficient workflows that handle complex tasks by breaking them into interdependent subtasks.
+
+## Overview
+
+Composite patterns allow agents to work in hybrid modes where some tasks run sequentially (one after another) while others execute in parallel (simultaneously). This approach optimizes performance by running independent tasks concurrently and ensuring dependent tasks are handled in order.
+
+In this demo, the system plans personalized travel itineraries by combining parallel searches for travel components with sequential processing for itinerary creation.
+
+## How It Works
+
+The travel planning process uses a composite structure:
+
+1. **Traveler Root Agent** (Coordinator): Receives user requests and delegates to the Trip Assistant Workflow.
+2. **Trip Assistant Workflow** (Sequential): First runs the Parallel Search Team, then the Itinerary Agent.
+3. **Parallel Search Team** (Parallel): Searches for flights, accommodations, and experiences concurrently.
+ - **Experiences** (Sequential): Within the parallel team, activities and dining are handled sequentially.
+
+## Flow Diagram
+
+```
+User Input
+ ↓
+TravelerRootAgent (Composite Patterns)
+ ↓
+TripAssistantWorkflow (Sequential)
+ ├─→ ParallelSearchTeam (Parallel)
+ │ ├─→ FlightAgent (with Search Tool)
+ │ ├─→ Experiences (Sequential)
+ │ │ ├─→ ActivityAgent (with Search & Maps Tools)
+ │ │ └─→ DiningAgent (with Search & Maps Tools)
+ │ └─→ AccommodationAgent (with Maps Tool)
+ └─→ ItineraryAgent
+ ↓
+Travel Itinerary Output
+```
+
+## Agents
+
+- **TravelerRootAgent**: Main coordinator that gathers requirements and delegates planning.
+- **FlightAgent**: Searches for flight options using web search tools.
+- **AccommodationAgent**: Finds lodging options using maps tools.
+- **ActivityAgent**: Discovers local activities and attractions.
+- **DiningAgent**: Recommends restaurants and dining experiences.
+- **ItineraryAgent**: Compiles all search results into a cohesive travel itinerary.
+
+## Running the Project
+
+1. Ensure you have Maven installed.
+2. Navigate to the project directory.
+3. Compile and run:
+
+```bash
+cd contrib/multi-agent-patterns
+mvn compile exec:java -Dexec.mainClass=com.google.adk.agents.traveler.TravelerApp
+```
+
+The application starts a web server where you can interact with the agents.
+
+## Example Usage
+
+Try prompts like:
+- "Plan a 5-day trip to Rome in July with a budget of $3000 for two people"
+
+## Configuration
+
+Agent configurations are defined in YAML files under `src/main/resources/agents/traveler/`:
+- `root-agent.yaml`: Traveler Root Agent configuration
+- `flight-agent.yaml`: Flight search agent
+- `accommodation-agent.yaml`: Accommodation search agent
+- `activity-agent.yaml`: Activity recommendations agent
+- `dining-agent.yaml`: Dining recommendations agent
+- `itinerary-agent.yaml`: Itinerary compilation agent
+
+## Dependencies
+
+- ADK Core
+- ADK Dev (for web UI)
+- Search and Maps tools for travel research
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/TravelerApp.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/TravelerApp.java
new file mode 100644
index 000000000..b376200d1
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/TravelerApp.java
@@ -0,0 +1,18 @@
+package com.google.adk.agents.traveler;
+
+import com.google.adk.agents.base.AgentConfigsProvider;
+import com.google.adk.web.AdkWebServer;
+
+/*
+ * run command:
+ * cd contrib/multi-agent-patterns
+ * mvn compile exec:java -Dexec.mainClass=com.google.adk.agents.traveler.TravelerApp
+ */
+public class TravelerApp {
+
+ public static void main(String[] args) throws Exception {
+ AgentConfigsProvider configs = new AgentConfigsProvider();
+ TravelerRootAgent root = new TravelerRootAgent(configs.get());
+ AdkWebServer.start(root.get());
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/TravelerRootAgent.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/TravelerRootAgent.java
new file mode 100644
index 000000000..ac9b0a9a2
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/TravelerRootAgent.java
@@ -0,0 +1,49 @@
+package com.google.adk.agents.traveler;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableMap.copyOf;
+import static java.util.Arrays.asList;
+
+import com.google.adk.agents.LlmAgent;
+import com.google.adk.agents.ParallelAgent;
+import com.google.adk.agents.SequentialAgent;
+import com.google.adk.agents.base.AgentConfig;
+import com.google.adk.agents.base.AgentContext;
+import com.google.adk.agents.base.LlmAgentProvider;
+import com.google.common.collect.ImmutableMap;
+import jakarta.inject.Provider;
+import java.util.Map;
+
+public class TravelerRootAgent implements Provider {
+
+ private static final String TRA_KEY = "traveler.root.agent";
+ private static final String TIA_KEY = "traveler.itinerary.agent";
+
+ public TravelerRootAgent(Map configs) {
+ this.configs = copyOf(checkNotNull(configs, "configs"));
+ }
+
+ private final ImmutableMap configs;
+
+ @Override
+ public LlmAgent get() {
+ SequentialAgent subAgent = tripAssistant(configs);
+ AgentConfig rootConfig = configs.get(TRA_KEY);
+ AgentContext rootCtx =
+ AgentContext.builder() //
+ .withConfig(rootConfig) //
+ .withSubAgents(asList(subAgent)) //
+ .build(); //
+ return new LlmAgentProvider(rootCtx).get();
+ }
+
+ private SequentialAgent tripAssistant(Map configs) {
+ ParallelAgent team = new TripSearchTeam(configs).get();
+ LlmAgent itinerary = new LlmAgentProvider(configs.get(TIA_KEY)).get();
+ return SequentialAgent.builder() //
+ .name("TripAssistantWorkflow") //
+ .description("Travel Planning Agent with parallel search") //
+ .subAgents(team, itinerary) //
+ .build();
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/TripSearchTeam.java b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/TripSearchTeam.java
new file mode 100644
index 000000000..84c384f29
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/java/com/google/adk/agents/traveler/TripSearchTeam.java
@@ -0,0 +1,72 @@
+package com.google.adk.agents.traveler;
+
+import static com.google.common.collect.ImmutableMap.copyOf;
+
+import com.google.adk.agents.LlmAgent;
+import com.google.adk.agents.ParallelAgent;
+import com.google.adk.agents.SequentialAgent;
+import com.google.adk.agents.base.AgentConfig;
+import com.google.adk.agents.base.AgentContext;
+import com.google.adk.agents.base.LlmAgentProvider;
+import com.google.adk.agents.base.tools.MapsAgentToolProvider;
+import com.google.adk.agents.base.tools.SearchAgentToolProvider;
+import com.google.adk.tools.AgentTool;
+import com.google.adk.tools.BaseTool;
+import com.google.common.collect.ImmutableMap;
+import jakarta.inject.Provider;
+import java.util.Map;
+
+public class TripSearchTeam implements Provider {
+
+ private static final String DESC =
+ """
+ The ParallelSearchTeam agent searches flights,
+ accommodations, dining and activity options concurrently.
+ """;
+
+ private static final String TFA_KEY = "traveler.flight.agent";
+ private static final String TAA_KEY = "traveler.accommodation.agent";
+ private static final String TEA_KEY = "traveler.activity.agent";
+ private static final String TDA_KEY = "traveler.dining.agent";
+
+ public TripSearchTeam(Map configs) {
+ this.configs = copyOf(configs);
+ }
+
+ private final ImmutableMap configs;
+
+ @Override
+ public ParallelAgent get() {
+ AgentTool maps = new MapsAgentToolProvider(configs).get();
+ AgentTool search = new SearchAgentToolProvider(configs).get();
+ LlmAgent flights = llmAgent(TFA_KEY, search);
+ SequentialAgent experiences = experiences();
+ LlmAgent accommodation = llmAgent(TAA_KEY, maps);
+ return ParallelAgent.builder() //
+ .name("ParallelSearchTeam") //
+ .description(DESC) //
+ .subAgents(flights, experiences, accommodation) //
+ .build();
+ }
+
+ private SequentialAgent experiences() {
+ AgentTool maps = new MapsAgentToolProvider(configs).get();
+ AgentTool search = new SearchAgentToolProvider(configs).get();
+ LlmAgent activities = llmAgent(TEA_KEY, search);
+ LlmAgent dining = llmAgent(TDA_KEY, maps);
+ return SequentialAgent.builder() //
+ .name("Activities and Dining") //
+ .subAgents(activities, dining) //
+ .build();
+ }
+
+ private LlmAgent llmAgent(String key, BaseTool... tools) {
+ AgentConfig config = configs.get(key);
+ AgentContext ctx =
+ AgentContext.builder() //
+ .withConfig(config) //
+ .withTools(tools) //
+ .build(); //
+ return new LlmAgentProvider(ctx).get();
+ }
+}
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/bundler-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/bundler-agent.yaml
new file mode 100644
index 000000000..8de2b545b
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/bundler-agent.yaml
@@ -0,0 +1,35 @@
+name: CodeBundlerAgent
+model: gemini-2.5-flash
+description: |
+ An aggregator agent that synthesizes code snippets
+ into a single, cohesive, and professionally
+ formatted multi-language report.
+instruction: |
+ **ROLE:**
+ You are the Code Reporter.
+
+ **GOAL:**
+ Take the outputs provided by the
+ code generasion and code conversion workflows
+ and combine them into a single, unified
+ Markdown-formatted output.
+
+ **TASK:**
+ Combine the generated and converted code into a single document.
+ For each language, provide a clear header and the
+ code enclosed in triple backticks.
+
+ **INPUT:**
+ **Generated Code:**
+ {generated_code}
+
+ **Converted Code:**
+ {converted_code?}
+
+
+ **OUTPUT FORMAT:**
+ # [Language Name]
+ ```[language-id]
+ [Code Snippet]
+ ```
+outputKey: code_report
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/converter-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/converter-agent.yaml
new file mode 100644
index 000000000..286f1e4c6
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/converter-agent.yaml
@@ -0,0 +1,53 @@
+name: CodeConverterAgent
+model: gemini-2.5-flash
+description: |
+ Converts generated code from one languate
+ to another programming language.
+instruction: |
+ **ROLE:**
+ You are a Code Translation Specialist.
+
+ **GOAL:**
+ Translate source code from one programming language to another
+ while maintaining identical logic, efficiency, and functionality.
+
+ **Code to Translate:**
+ {generated_code?}
+
+ **Translation Protocol:**
+ - Analyze Before Acting: Before writing the target code,
+ identify the core logic, data structures, and external
+ dependencies of the source snippet.
+ - Idiomatic Mapping: Do not translate literally.
+ Use the patterns and best practices of the target language
+ (e.g., use List comprehensions in Python, but standard for loops or Streams in Java).
+ - Type Management:
+ - If moving from a dynamic to a statically typed language
+ (e.g., Python to Java), infer types correctly and use appropriate wrappers or generics.
+ - If moving from static to dynamic, ensure the logic remains robust
+ without the safety net of explicit types.
+
+ **Structural Requirements:**
+ - Error Handling: Translate try-except blocks to the target's equivalent (e.g., try-catch).
+ Ensure specific exception types are mapped to their closest counterparts.
+ - Library Parity: If the source code uses standard libraries (like Python's math or datetime),
+ use the equivalent standard library in the target language. If a specialized library is used
+ (like pandas), provide a comment suggesting the target equivalent (like Tablesaw for Java).
+ - Naming Conventions: Convert variable names to fit the target language style
+ (e.g., snake_case for Python, camelCase for Java/JavaScript)
+
+ **CONSTRAINTS:**
+ - No Logic Alteration: Do not "optimize" the algorithm unless
+ it is necessary for the code to run in the target environment.
+ - Comment Preservation: Keep all original comments.
+ If a specific line is complex to translate, add
+ a brief comment explaining the implementation choice.
+ - Self-Correction:
+ If a feature in the source language has no direct equivalent
+ (e.g., Python's multiple inheritance in a language that doesn't support it),
+ use a standard workaround (like Interfaces) and flag it to the user.
+
+ **OUTPUT FORMAT:**
+ - Refactored Code block enclosed in triple backticks (e.g., ```java ... ```).
+ - Do not add any other text before or after the code block.
+outputKey: converted_code
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/critic-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/critic-agent.yaml
new file mode 100644
index 000000000..0db327b83
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/critic-agent.yaml
@@ -0,0 +1,30 @@
+name: CodeCriticAgent
+model: gemini-2.5-flash
+description: |
+ Reviews converted code for
+ correctness and provides feedback
+instruction: |
+ **ROLE:**
+ You are an expert Code Reviewer.
+ You read, analyze, and report findings
+ with severity rankings.
+
+ **GOAL:**
+ Review converted code and provide
+ constructive feedback focused on
+ correctness and style.
+
+ **Code to Review:**
+ {converted_code}
+
+ **WORKFLOW:**
+ 1. Correctness: Check correctness against the problem statement or original code
+ 2. Readability: Does the code follow the requested language style guidelines?
+ 5. Best Practices: Does the code follow common the requested language best practices?
+
+ **OUTPUT FORMAT:**
+ - Your feedback as a bulleted list (critical to low)
+ - IF the code is excellent and no changes required,
+ you MUST respond with the exact phrase: "APPROVED"
+ Output ONLY the review comments or the "APPROVED" statement.
+outputKey: critique
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/generator-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/generator-agent.yaml
new file mode 100644
index 000000000..a624b1de8
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/generator-agent.yaml
@@ -0,0 +1,33 @@
+name: CodeGeneratorAgent
+model: gemini-2.5-flash
+description: |
+ A highly skilled software professional capable of architecting,
+ writing, and refactoring code across multiple programming
+ languages with a focus on best practices and efficiency.
+instruction: |
+ **ROLE:**
+ You are an expert software engineer.
+
+ **GOAL:**
+ Produce correct, maintainable code
+ that satisfies the problem statement.
+
+ **INPUT:**
+ - Problem Statement: what to build or to change/refactor
+ - Constraints?: (e.g. min/max values of input parameters, input size etc)
+
+ **TASK:**
+ Your task is to write high-quality, production-ready code based on the user requirements.
+ 1. Implement the logic using industry-standard design patterns and clean code principles.
+ 2. Include necessary comments explaining complex logic.
+ 3. Ensure the code is performant and handles potential edge cases or errors.
+ 4. Provide only the code block in the final output unless specifically asked for an explanation.
+
+ **WORKFLOW:**
+ 1. Restate the task in 1-2 lines.
+ 2. Implement or update code with safe defaults and clear naming.
+
+ **OUTPUT FORMAT:**
+ - Generated Code block enclosed in triple backticks (e.g., ```python ... ```).
+ - Do not add any other text before or after the code block.
+outputKey: generated_code
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/prompt-fibonacci.md b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/prompt-fibonacci.md
new file mode 100644
index 000000000..2a37569e8
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/prompt-fibonacci.md
@@ -0,0 +1,98 @@
+## Prompt: 509. Fibonacci Number
+Solve the Fibnacci problem.
+Write code in Java and convert to Python:
+
+The Fibonacci numbers, commonly denoted F(n) form a sequence,
+called the Fibonacci sequence, such that each number is
+the sum of the two preceding ones, starting from 0 and 1. That is,
+F(0) = 0, F(1) = 1
+F(n) = F(n - 1) + F(n - 2), for n > 1.
+Given n, calculate F(n).
+
+Constraints:
+0 <= n <= 30
+
+## Response
+Here is the Java code for the Fibonacci problem and its conversion to Python:
+
+# JAVA
+```
+ /**
+ * Calculates the nth Fibonacci number.
+ * The Fibonacci numbers, commonly denoted F(n) form a sequence,
+ * called the Fibonacci sequence, such that each number is
+ * the sum of the two preceding ones, starting from 0 and 1.
+ * F(0) = 0, F(1) = 1
+ * F(n) = F(n - 1) + F(n - 2), for n > 1.
+ *
+ * @param n The index of the Fibonacci number to calculate.
+ * @return The nth Fibonacci number.
+ * @throws IllegalArgumentException if n is less than 0 or greater than 30.
+ */
+
+public class Solution {
+ public int fib(int n) {
+ // Constraints: 0 <= n <= 30
+ if (n < 0 || n > 30) {
+ throw new IllegalArgumentException("Input n must be between 0 and 30, inclusive.");
+ }
+
+ // Base cases
+ if (n == 0) {
+ return 0;
+ }
+ if (n == 1) {
+ return 1;
+ }
+
+ // Iterative approach to calculate Fibonacci numbers
+ int a = 0; // Represents F(i-2)
+ int b = 1; // Represents F(i-1)
+ int result = 0; // Represents F(i)
+
+ // Start from i = 2, as F(0) and F(1) are already handled
+ for (int i = 2; i <= n; i++) {
+ result = a + b; // F(i) = F(i-2) + F(i-1)
+ a = b; // Update F(i-2) to be the previous F(i-1)
+ b = result; // Update F(i-1) to be the current F(i)
+ }
+
+ return result;
+ }
+}
+```
+# PYTHON
+```
+class Solution:
+ """
+ Calculates the nth Fibonacci number.
+ The Fibonacci numbers, commonly denoted F(n) form a sequence,
+ called the Fibonacci sequence, such that each number is
+ the sum of the two preceding ones, starting from 0 and 1.
+ F(0) = 0, F(1) = 1
+ F(n) = F(n - 1) + F(n - 2), for n > 1.
+ """
+ def fib(self, n: int) -> int:
+ # Constraints: 0 <= n <= 30
+ if not (0 <= n <= 30):
+ raise ValueError("Input n must be between 0 and 30, inclusive.")
+
+ # Base cases
+ if n == 0:
+ return 0
+ if n == 1:
+ return 1
+
+ # Iterative approach to calculate Fibonacci numbers
+ a = 0 # Represents F(i-2)
+ b = 1 # Represents F(i-1)
+ result = 0 # Represents F(i)
+
+ # Start from i = 2, as F(0) and F(1) are already handled
+ for _ in range(2, n + 1):
+ result = a + b # F(i) = F(i-2) + F(i-1)
+ a = b # Update F(i-2) to be the previous F(i-1)
+ b = result # Update F(i-1) to be the current F(i)
+
+ return result
+```
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/prompt-stock-price-fluctuation.md b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/prompt-stock-price-fluctuation.md
new file mode 100644
index 000000000..ec1c2cab9
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/prompt-stock-price-fluctuation.md
@@ -0,0 +1,204 @@
+## PROMPT: 2034. Stock Price Fluctuation
+#### PROMLEM STATEMENT:
+You are given a stream of records about a particular stock.
+Each record contains a timestamp and the corresponding price of the stock at that timestamp.
+
+Unfortunately due to the volatile nature of the stock market,
+the records do not come in order. Even worse, some records may be incorrect.
+Another record with the same timestamp may appear later in the stream correcting the price of the previous wrong record.
+
+Design an algorithm that:
+
+Updates the price of the stock at a particular timestamp, correcting the price from any previous records at the timestamp.
+Finds the latest price of the stock based on the current records. The latest price is the price at the latest timestamp recorded.
+Finds the maximum price the stock has been based on the current records.
+Finds the minimum price the stock has been based on the current records.
+Implement the StockPrice class:
+
+StockPrice() Initializes the object with no price records.
+- void update(int timestamp, int price) Updates the price of the stock at the given timestamp.
+- int current() Returns the latest price of the stock.
+- int maximum() Returns the maximum price of the stock.
+- int minimum() Returns the minimum price of the stock.
+
+Constraints:
+- 1 <= timestamp, price <= 10^9
+- At most 105 calls will be made in total to update, current, maximum, and minimum.
+- current, maximum, and minimum will be called only after update has been called at least once.
+
+Please refactor the following code in Java:
+
+```class StockPrice {
+
+ private int maxTimestamp;
+ private TreeMap prices;
+ private TreeMap counts;
+
+ public StockPrice() {
+ this.maxTimestamp = 0;
+ this.counts = new TreeMap<>();
+ this.prices = new TreeMap<>();
+ }
+
+ public void update(int timestamp, int price) {
+ if (prices.containsKey(timestamp)) {
+ int prev = prices.get(timestamp);
+ counts.put(prev, counts.get(prev) - 1);
+ if (counts.get(prev) == 0) {
+ counts.remove(prev);
+ }
+ }
+ prices.put(timestamp, price);
+ counts.put(price, counts.getOrDefault(price, 0) + 1);
+ maxTimestamp = Math.max(maxTimestamp, timestamp);
+ }
+
+ public int current() {
+ return prices.get(maxTimestamp);
+ }
+
+ public int maximum() {
+ return counts.lastKey();
+ }
+
+ public int minimum() {
+ return counts.firstKey();
+ }
+}
+```
+
+# CodeRootAgent
+I have refactored the Java code for the StockPrice class.
+
+## Here are the key changes and improvements:
+
+- Helper Methods for Price Frequency Management: Introduced decrementPriceFrequency(int price) and incrementPriceFrequency(int price) to encapsulate the logic for updating price counts. This makes the update method cleaner and more readable.
+
+- Error Handling for current(): Added a check in the current() method to throw an IllegalStateException if no prices have been updated yet. This prevents a NullPointerException that could occur if prices.get(maxTimestamp) is called when prices is empty.
+
+- Clarity and Comments: Added Javadoc comments to explain the purpose of the class, its fields, and each method, improving code understanding and maintainability.
+
+- Renamed counts: The counts TreeMap was renamed from priceFrequencies to match the original code, ensuring consistency.
+The refactored code is as follows:
+
+```
+import java.util.TreeMap;
+import java.util.NoSuchElementException; // Not directly used for the fix, but good to be aware of the original exception type.
+
+/**
+ * Manages stock prices, allowing updates and retrieval of current, maximum, and minimum prices.
+ * This class uses TreeMaps to efficiently store and retrieve sorted data.
+ */
+class StockPrice {
+
+ // Stores the maximum timestamp encountered so far.
+ private int maxTimestamp;
+ // Maps timestamp to its corresponding price. Used for efficient lookup by timestamp.
+ private TreeMap prices;
+ // Maps price to its frequency (count of occurrences). Used for efficient retrieval of min/max prices.
+ private TreeMap counts; // Renamed from priceFrequencies to match original code
+
+ /**
+ * Initializes a new StockPrice instance.
+ * Sets the initial maximum timestamp to 0 and initializes the TreeMaps.
+ */
+ public StockPrice() {
+ this.maxTimestamp = 0;
+ this.counts = new TreeMap<>();
+ this.prices = new TreeMap<>();
+ }
+
+ /**
+ * Updates the price for a given timestamp.
+ * If the timestamp already exists, its old price's frequency is decremented.
+ * The new price's frequency is then incremented.
+ * The maximum timestamp is updated if the current timestamp is greater.
+ *
+ * @param timestamp The timestamp for which to update the price.
+ * @param price The new price for the given timestamp.
+ */
+ public void update(int timestamp, int price) {
+ // If the timestamp already has a price, we need to adjust its frequency.
+ if (prices.containsKey(timestamp)) {
+ int oldPrice = prices.get(timestamp);
+ decrementPriceFrequency(oldPrice); // Helper method to decrement frequency
+ }
+
+ // Store the new price for the given timestamp.
+ prices.put(timestamp, price);
+ // Increment the frequency of the new price.
+ incrementPriceFrequency(price); // Helper method to increment frequency
+
+ // Update the maximum timestamp seen so far.
+ maxTimestamp = Math.max(maxTimestamp, timestamp);
+ }
+
+ /**
+ * Retrieves the current price, which is the price associated with the maximum timestamp.
+ *
+ * @return The price at the latest timestamp.
+ * @throws IllegalStateException if no prices have been updated yet.
+ */
+ public int current() {
+ // Critical fix: Handle case where no prices have been updated yet.
+ // If prices is empty, maxTimestamp might be 0, and prices.get(0) would return null,
+ // leading to NullPointerException on unboxing.
+ if (prices.isEmpty()) {
+ throw new IllegalStateException("No prices have been updated yet.");
+ }
+ // The current price is always the price at the latest recorded timestamp.
+ return prices.get(maxTimestamp);
+ }
+
+ /**
+ * Retrieves the maximum price recorded among all prices.
+ * This is efficiently found using the last key of the counts TreeMap.
+ *
+ * @return The highest price recorded.
+ * @throws IllegalStateException if no prices have been updated yet.
+ */
+ public int maximum() {
+ if (counts.isEmpty()) {
+ throw new IllegalStateException("No prices have been updated yet.");
+ }
+ return counts.lastKey();
+ }
+
+ /**
+ * Retrieves the minimum price recorded among all prices.
+ * This is efficiently found using the first key of the counts TreeMap.
+ *
+ * @return The lowest price recorded.
+ * @throws IllegalStateException if no prices have been updated yet.
+ */
+ public int minimum() {
+ if (counts.isEmpty()) {
+ throw new IllegalStateException("No prices have been updated yet.");
+ }
+ return counts.firstKey();
+ }
+
+ /**
+ * Helper method to decrement the frequency of a given price in the counts TreeMap.
+ * If the frequency becomes 0, the price is removed from the map.
+ *
+ * @param price The price whose frequency needs to be decremented.
+ */
+ private void decrementPriceFrequency(int price) {
+ counts.put(price, counts.get(price) - 1);
+ if (counts.get(price) == 0) {
+ counts.remove(price);
+ }
+ }
+
+ /**
+ * Helper method to increment the frequency of a given price in the counts TreeMap.
+ * If the price is new, it's added with a frequency of 1.
+ *
+ * @param price The price whose frequency needs to be incremented.
+ */
+ private void incrementPriceFrequency(int price) {
+ counts.put(price, counts.getOrDefault(price, 0) + 1);
+ }
+}
+```
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/refactor-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/refactor-agent.yaml
new file mode 100644
index 000000000..072650ec9
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/refactor-agent.yaml
@@ -0,0 +1,31 @@
+name: CodeRefactorAgent
+model: gemini-2.5-flash
+description: |
+ Refactors converted code based on
+ review findings while preserving behavior.
+instruction: |
+ **ROLE:**
+ You are a Code Refactor Agent.
+
+ **GOAL:**
+ Improve internal code quality -
+ reduce duplication, simplify complexity
+ and increase readability - while preserving behavior.
+
+ **Code to Refactor:**
+ {converted_code}
+
+ **Review Comments:**
+ {critique}
+
+ **WORKFLOW:**
+ 1. Apply high-severity review fixes first.
+ 2. Reduce complexity and duplication with minimal structural changes.
+ 3. Preserve external behavior and contracts.
+ 4. Add short comments on what changed and why.
+ 5. If the review comments state "APPROVED", return the original code.
+
+ **OUTPUT FORMAT:**
+ - Refactored Code block enclosed in triple backticks (e.g., ```java ... ```).
+ - Do not add any other text before or after the code block.
+outputKey: converted_code
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/refiner-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/refiner-agent.yaml
new file mode 100644
index 000000000..a1ba6034e
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/refiner-agent.yaml
@@ -0,0 +1,41 @@
+name: CodeRefinerAgent
+model: gemini-2.5-flash
+description: |
+ Refactors generated code based on
+ review findings while preserving behavior.
+instruction: |
+ **ROLE:**
+ You are a Refiner Code Agent.
+
+ **GOAL:**
+ Improve internal code quality -
+ improve time and space complexities,
+ reduce duplication,
+ simplify overall code complexity
+ and increase readability - while preserving behavior.
+
+ **Code to Refactor:**
+ {generated_code}
+
+ **Review Feedback:**
+ {review_feedback}
+
+ **TAKS:**
+ Your task is to analyze the review comments.
+ - IF the review is EXACTLY "APPROVED",
+ you MUST call the `exit_loop` function
+ and nothing else. Do NOT output any text.
+ - ELSE
+ - apply high-severity review fixes first
+ - reduce complexity and duplication with minimal structural changes
+ - preserve external behavior and contracts
+ - add short comments on what changed and why
+
+ You MUST EITHER call `exit_loop` OR output
+ refactored version of the code.
+ Never do both in the same response.
+
+ **OUTPUT FORMAT:**
+ - Refactored Code block enclosed in triple backticks (e.g., ```java ... ```).
+ - Do not add any other text before or after the code block.
+outputKey: generated_code
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/review-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/review-agent.yaml
new file mode 100644
index 000000000..7467d9808
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/review-agent.yaml
@@ -0,0 +1,34 @@
+name: CodeReviewerAgent
+model: gemini-2.5-flash
+description: |
+ Reviews generated code for
+ correctness and performance
+ and provides feedback
+instruction: |
+ **ROLE:**
+ You are an expert Code Reviewer
+ You read, analyze, and report findings
+ with severity rankings.
+
+ **GOAL:**
+ Review generated code and provide
+ constructive feedback focused on bugs,
+ performance, data structures,
+ algorithms, and style.
+
+ **Code to Review:**
+ {generated_code}
+
+ **WORKFLOW:**
+ 1. Correctness: Check correctness against the problem statement.
+ 2. Readability: Does the code follow language specific style guidelines?
+ 3. Efficiency: Is the code efficient? Can we do better?
+ 4. Edge Cases: Does the code handle potential edge cases or invalid inputs gracefully?
+ 5. Best Practices: Does the code follow common language specific best practices?
+
+ **OUTPUT FORMAT:**
+ - Your feedback as a bulleted list (critical to low)
+ - IF the code is excellent and no changes required,
+ you MUST respond with the exact phrase: "APPROVED"
+ Output ONLY the review comments or the "APPROVED" statement.
+outputKey: review_feedback
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/root-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/root-agent.yaml
new file mode 100644
index 000000000..cee364af0
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/code/root-agent.yaml
@@ -0,0 +1,41 @@
+name: CodeRootAgent
+model: gemini-2.5-flash
+description: |
+ Central Orchestrator that routes tasks to
+ specialized agents based on the user' requests
+instruction: |
+ **ROLE:**
+ You are a Code Dispatcher Agent
+ that helps developers and engineers
+ write high quality code and perform
+ code convertion tasks from one language to another.
+
+ **TASK:**
+ 1. Identify the requested input programming language.
+ If user provides problem statement,
+ ask in what programming language to generate the code.
+ Use Python as default if user does not specify
+ and inform the user about the default choice.
+
+ If user provides the code and asks to refactor it
+ first try to identify the programming language yourself
+ and ALWAYS confirm the input language with user before proceeding.
+ If you can not recognize the input language,
+ just ask the user for help.
+ If you are unfamiliar with the input language,
+ just say you are not familiar with the language and
+ can not help with the request.
+
+ If user input includes code convertion request,
+ confirm with the user what language to convert the code to.
+
+ 2. Do not do any of the tasks yourself.
+ You delegate code generation from problem statement requests to the CodeGenerationWorkflow.
+ You delegate code refactoring requests to the CodeGenerationWorkflow.
+ You delegate code convertion requests to the CodeConversionWorkflow.
+ You delegate code generation and convertion requests to the FullLoopWorkflow.
+
+ Follow these steps:
+ 1. If the user asks about generating or refactoring code, delegate to the CodeGenerationWorkflow
+ 2. If the user asks about converting code, delegate to the CodeConversionWorkflow.
+ 3. If the user asks about both generating and converting code, delegate to the FullLoopWorkflow.
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/content-analyst.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/content-analyst.yaml
new file mode 100644
index 000000000..9be3858d7
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/content-analyst.yaml
@@ -0,0 +1,27 @@
+name: ContentAnalyst
+model: gemini-2.5-flash
+description: An agent that analyses the research results
+instruction: |
+ **ROLE:**
+ You are a professional content summarizer,
+ analyst and researcher. Use a neutral,
+ informative tone.
+
+ **GOAL:**
+ Summarize the research findings on
+ the requested topic into a condensed text
+
+ **Topic Research:**
+ {topic_research}
+
+ **TASK:**
+ Read the provided documents carefully and
+ generate a concise summary that captures
+ the main ideas, findings, and critical insights.
+
+ **OUTPUT FORMAT:**
+ - Place a top-level summary at the beginning
+ - Use bullet points for key facts, and short
+ thematic paragraphs for context
+ - Extract 3-5 relevant keywords or tags at the end
+transferToAgent: ResearchCoordinatorAgent
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/prompt-ai.md b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/prompt-ai.md
new file mode 100644
index 000000000..4a18e4f61
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/prompt-ai.md
@@ -0,0 +1,32 @@
+## User
+Write a report on artificial intelligence
+
+## ReportWriterAgent
+I will write a comprehensive report on Artificial intelligence
+
+# Report on Artificial Intelligence
+
+## Introduction
+
+Artificial Intelligence (AI) represents a transformative field of computer science dedicated to creating machines capable of performing tasks that typically require human intelligence. From its inception, AI has evolved significantly, moving from theoretical concepts to practical applications that are reshaping industries and daily life. This report will delve into the origins of AI, its remarkable capabilities, its profound economic impact, and the critical ethical considerations that accompany its advancement.
+
+## The Genesis of Artificial Intelligence
+
+The formal journey of artificial intelligence began in the mid-20th century. The term "artificial intelligence" was officially coined in 1955, laying the groundwork for a new academic discipline. The field publicly debuted at the Dartmouth Conference in 1956, an event widely regarded as the formal birth of AI research. This pivotal conference brought together pioneers who envisioned machines that could simulate human cognitive functions, setting the stage for decades of innovation and development.
+
+## Capabilities and Rapid Advancement
+
+One of the most defining characteristics of modern AI systems is their extraordinary capacity for learning and processing information. AI can learn at an incredibly fast pace, analyzing and extracting insights from massive datasets in a matter of seconds—a feat unattainable by humans. This rapid learning capability is fundamental to the continuous stream of AI-driven innovations witnessed today. From natural language processing and image recognition to complex predictive analytics, AI's ability to quickly adapt and improve fuels its diverse applications across various sectors.
+
+## Economic Impact and Future Projections
+
+The economic ramifications of artificial intelligence are nothing short of monumental. Projections indicate that the global AI market is poised for explosive growth, expected to surpass a staggering $1 trillion. Furthermore, AI is anticipated to contribute an astounding $15.7 trillion to the global economy by 2030. This immense economic contribution will be driven by two primary factors: significant productivity gains across industries and a surge in consumer demand for AI-enhanced products and services. AI is not just a technological advancement; it is a powerful economic engine reshaping global commerce and value creation.
+
+## Ethical Considerations and Challenges
+
+Despite its immense potential, the proliferation of AI also presents significant ethical challenges that demand careful attention. A critical concern is the ability of AI systems to inherit and amplify human biases present in their training data. If the data used to train an AI contains biases related to race, gender, ethnicity, or any other demographic, the AI can learn, perpetuate, and even scale these biases into its decision-making processes. This phenomenon underscores the urgent need for diverse and representative training data, as well as robust ethical oversight in the development and deployment of AI technologies. Addressing these biases is crucial to ensure that AI systems are fair, equitable, and beneficial for all segments of society.
+
+## Conclusion
+
+Artificial intelligence stands as one of the most transformative technologies of our time. From its conceptual origins in the mid-20th century to its current state of rapid evolution, AI continues to redefine what is possible. Its capacity for quick learning and data processing drives innovation and promises substantial economic growth. However, the ethical imperative to address inherent biases and ensure responsible development remains paramount. As AI continues to advance, a balanced approach that fosters innovation while upholding ethical standards will be essential for harnessing its full potential for the betterment of humanity.
+
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/prompt-self-driving-cars.md b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/prompt-self-driving-cars.md
new file mode 100644
index 000000000..d4cb95326
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/prompt-self-driving-cars.md
@@ -0,0 +1,37 @@
+## User
+Write a report on self-driving cars
+
+## ReportWriterAgent
+I will write a comprehensive report on self-driving cars.
+
+# Report on Self-Driving Cars
+
+## 1. Introduction
+Self-driving cars, also known as autonomous vehicles, represent a transformative technology poised to revolutionize transportation. These vehicles are designed to operate without human intervention, utilizing a combination of sensors, cameras, radar, lidar, and artificial intelligence to perceive their surroundings and navigate. The development of self-driving cars promises significant advancements in safety, efficiency, and accessibility, fundamentally altering urban planning, logistics, and personal mobility.
+
+## 2. Levels of Autonomy
+The Society of Automotive Engineers (SAE) International has established a widely recognized classification system for vehicle autonomy, categorizing self-driving capabilities into six levels, from Level 0 to Level 5:
+
+- Level 0 (No Automation): The human driver performs all driving tasks.
+- Level 1 (Driver Assistance): The vehicle can assist with either steering or braking/acceleration, but not both simultaneously (e.g., adaptive cruise control or lane keeping assist).
+- Level 2 (Partial Automation): The vehicle can control both steering and braking/acceleration under specific conditions, but the driver must remain engaged and ready to take over.
+- Level 3 (Conditional Automation): The vehicle can perform all driving tasks under specific conditions, and the driver is not required to monitor the environment constantly but must be ready to intervene when prompted.
+- Level 4 (High Automation): The vehicle can perform all driving tasks and monitor the driving environment under specific conditions (e.g., within a geofenced area). The driver is not expected to intervene.
+- Level 5 (Full Automation): The vehicle can perform all driving tasks under all driving conditions, equivalent to a human driver. No human intervention is required.
+
+## 3. Current State of Technology
+As of late 2025, the landscape of self-driving technology shows significant progress, though full Level 5 autonomy remains an aspirational goal. While no system has yet achieved complete Level 5 capabilities, Level 3 vehicles are commercially available, offering conditional automation where the vehicle can handle most driving tasks under specific circumstances, but still requires driver readiness for intervention. More advanced Level 4 robo-taxis are already operating commercially in select cities, demonstrating high automation within defined operational design domains. Companies like Waymo have accumulated millions of miles on public roads with their autonomous fleets, showcasing the practical application and safety potential of these systems.
+
+## 4. Market Overview and Growth
+The autonomous vehicle market is experiencing robust growth, reflecting increasing investment and technological advancements. In 2025, the global autonomous vehicle market was valued at an impressive USD 2.3 trillion. Projections indicate a substantial expansion, with the market expected to reach USD 8.4 trillion by 2035. This growth trajectory represents a significant compound annual growth rate (CAGR) of 13.9%, underscoring the immense economic potential and anticipated widespread adoption of self-driving technologies in the coming decade.
+
+## 5. Challenges and Obstacles
+Despite the rapid advancements, the widespread deployment of self-driving cars faces several significant challenges:
+
+- **Absence of Consistent Regulations:** A lack of uniform regulatory frameworks across different regions and countries creates uncertainty for manufacturers and operators, hindering large-scale deployment and standardization.
+- **Consumer Trust Issues:** Public perception and trust remain critical hurdles. Concerns about safety, particularly following high-profile incidents involving autonomous vehicles, necessitate rigorous testing, transparent communication, and demonstrable reliability to build consumer confidence.
+- **Technological Limitations (Edge Cases):** While autonomous systems excel in predictable environments, they still struggle with complex "edge cases"—unusual or unforeseen scenarios that are difficult to program for, such as unpredictable human behavior, extreme weather conditions, or unusual road debris.
+- **High Costs:** The advanced sensor suites, powerful computing hardware, and sophisticated software required for autonomous systems are currently very expensive, contributing to the high cost of self-driving vehicles and services. Reducing these costs will be crucial for broader market penetration.
+
+## 6. Conclusion
+Self-driving cars represent a frontier of innovation with the potential to redefine transportation. While significant progress has been made, particularly with the commercial operation of Level 4 robo-taxis and the availability of Level 3 vehicles, the journey to full Level 5 autonomy is ongoing. Addressing the multifaceted challenges related to regulation, consumer trust, technological limitations, and cost will be paramount for realizing the full benefits of this transformative technology. As research and development continue, self-driving cars are poised to play an increasingly vital role in shaping the future of mobility.
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/research-coordinator.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/research-coordinator.yaml
new file mode 100644
index 000000000..d9fc56b56
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/research-coordinator.yaml
@@ -0,0 +1,27 @@
+name: ResearchCoordinatorAgent
+model: gemini-2.5-flash
+description: |
+ An agent that finds and summarizes info
+instruction: |
+ **ROLE:**
+ You are a Research Coordinator
+ You have two assistants to help with
+ information search and analysis
+
+ **GOAL:**
+ Find and summarize information
+ on a requested topic.
+
+ **WORKFLOW:**
+ 1. Do not conduct research youself
+ Use the `TopicResearcher` agent to find information
+ about requested topic
+
+ 2. Do not conduct the analysis yourself
+ Use the `ContentAnalyst` agent to craft a summary
+ about requested topic
+
+ 3. Do not create the report yourself
+ Collect the final summary outline
+ and return it to the `ReportWriterAgent`
+transferToAgent: ReportWriterAgent
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/root-writer.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/root-writer.yaml
new file mode 100644
index 000000000..c7139d6c0
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/root-writer.yaml
@@ -0,0 +1,27 @@
+name: ReportWriterAgent
+model: gemini-2.5-flash
+description: |
+ An agent that writes the full report
+instruction: |
+ **ROLE:**
+ You are an experienced report writer.
+
+ **GOAL:**
+ Write a comprehensive report on
+ a topic requested by the user.
+
+ **INPUT:**
+ - Research Topic
+
+ **WORKFLOW:**
+ 1. Restate the task in 1-2 lines.
+ 2. Delegate the research task to `ResearchCoordinatorAgent`
+ Do not conduct research youself
+ 3. Wait for the result and
+ create a comprehensive report
+ following the research summary outline
+ provided by the `ResearchCoordinatorAgent`,
+
+ **OUTPUT FORMAT:**
+ Output ONLY the final report text.
+outputKey: final_report
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/topic-researcher.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/topic-researcher.yaml
new file mode 100644
index 000000000..1c7204fb5
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/report/topic-researcher.yaml
@@ -0,0 +1,20 @@
+name: TopicResearcher
+model: gemini-2.5-flash
+description: An agent that researches a topic and gathers key information
+instruction: |
+ **ROLE:**
+ You are an expert research assistant
+ focused on gathering information
+ about the requested topic
+
+ **TASK:**
+ Use the `google_search` tool to
+ search up-to-date and relevant information
+ on the given topic. Focus on interesting,
+ specific and relevant information.
+ Be comprehensive but concise.
+
+ **OUTPUT FORMAT:**
+ Output a bulleted list of 3-4 key facts
+ or insights about the topic with citations.
+transferToAgent: ResearchCoordinatorAgent
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/tool/code-execution.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/tool/code-execution.yaml
new file mode 100644
index 000000000..be23218f6
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/tool/code-execution.yaml
@@ -0,0 +1,6 @@
+name: CodeExecutor
+model: gemini-2.5-flash
+description: An agent that generates code
+instruction: |
+ Produce correct, maintainable code
+ that satisfies the problem statement.
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/tool/maps-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/tool/maps-agent.yaml
new file mode 100644
index 000000000..c350cd982
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/tool/maps-agent.yaml
@@ -0,0 +1,10 @@
+name: GoogleMapsAgent
+model: gemini-2.5-flash
+description: An agent that searches on Google Maps
+instruction: |
+ Your role is to search on Google Maps.
+ Use the Google Maps Tool to search up-to-date
+ and relevant information about locations.
+ Focus: Maintain strict relevance to the requested topic.
+ No Hallucinations: If information is not available,
+ state that you do not know rather than creating a fake answer.
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/tool/search-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/tool/search-agent.yaml
new file mode 100644
index 000000000..c5819953a
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/tool/search-agent.yaml
@@ -0,0 +1,10 @@
+name: GoogleSearchAgent
+model: gemini-2.5-flash
+description: An agent that searches on Google Search
+instruction: |
+ Your role is to search on Google Search.
+ Use the Google Search Tool to search up-to-date
+ and relevant information about the topic.
+ Focus: Maintain strict relevance to the requested topic.
+ No Hallucinations: If information is not available,
+ state that you do not know rather than creating a fake answer.
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/accommodation-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/accommodation-agent.yaml
new file mode 100644
index 000000000..16684d91f
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/accommodation-agent.yaml
@@ -0,0 +1,28 @@
+name: AccomodationAgent
+model: gemini-2.5-flash
+description: An accomodation guide for travelers
+instruction: |
+ **ROLE:**
+ You are an accomodation guide for travelers.
+
+ **GOAL:**
+ Find and suggest suitable accomodation
+ for destination location
+
+ **TAKS:**
+ Use the `google_maps` tool to find hotels
+ at destination location
+
+ Your job is ONLY search for existing hotels
+ and provide 2-3 top options
+ Do NOT book a hotel
+
+ If no hotels found, just say
+ no options found
+
+ **OUTPUT FORMAT:**
+ Provide 2-3 options as a bulleted list
+ (sorted by price in ascending order) with
+ - Hotel name and rating
+ - Location (district/area)
+outputKey: accomodation_options
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/activity-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/activity-agent.yaml
new file mode 100644
index 000000000..c2ea7c98a
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/activity-agent.yaml
@@ -0,0 +1,28 @@
+name: ActivityAgent
+model: gemini-2.5-flash
+description: An activity guide for travelers
+instruction: |
+ **ROLE:**
+ You are a local activities expert.
+
+ **GOAL:**
+ Find and recommend activities and attractions
+ for each day of the trip.
+
+ **OPTIONAL PREFERENCES:**
+ e.g. Are you more into museums and history,
+ or outdoor adventures like hiking and kayaking?
+
+ **TASK:**
+ Use the `google_maps` tool to find dining places
+ that are near by the day's activities and fit in
+ the overall travel style and budget.
+
+ **OUTPUT FORMAT:**
+ Provide 3-4 activities as a bulleted list
+ grouped by proximity or theme for each day
+ in chronological order with
+ - Activity name
+ - Description (1 sentence)
+ - Estimated cost
+outputKey: activity_options
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/dining-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/dining-agent.yaml
new file mode 100644
index 000000000..2ab68de26
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/dining-agent.yaml
@@ -0,0 +1,31 @@
+name: DiningAgent
+model: gemini-2.5-flash
+description: A dining guide for travelers
+instruction: |
+ **ROLE:**
+ You are a dining guide for travelers.
+
+ **GOAL:**
+ Find and suggest one lunch and one dinner place
+ for each day of the trip.
+
+ **OPTIONAL PREFERENCES:**
+ - Dietary preferences or restrictions
+ - Comfortable daily food budget
+
+ **Recommended Activities:**
+ {activity_options?}
+
+ **TASK:**
+ Use the `google_maps` tool to find dining places
+ that are near by the day's activities if provided
+ or search based on requested destination
+ and fit in the overall travel style and budget.
+
+ **OUTPUT FORMAT:**
+ Provide 2-3 places as a bulleted list
+ (sorted by price in ascending order) with
+ - name
+ - location
+ - link to google maps
+outputKey: dining_options
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/flight-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/flight-agent.yaml
new file mode 100644
index 000000000..b19c3110a
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/flight-agent.yaml
@@ -0,0 +1,41 @@
+name: FlightAgent
+model: gemini-2.5-flash
+description: A flight guide for travelers
+instruction: |
+ **ROLE:**
+ You are a flight search agent.
+
+ **GOAL:**
+ Search flights, check availabilities and
+ provide flight options based on user input
+
+ **INPUT:**
+ - Departure
+ - Destination
+ - Travel dates
+ - Number of passengers (adults, children)
+
+ **OPTIONAL PREFERENCES:**
+ - Airlines
+ - Flexible dates
+ - Budget constraints
+
+ **TASK:**
+ Use the `google_search` tool to
+ search for available flights
+
+ Your job is ONLY search for available flights
+ and provide 2-3 top options
+ Do NOT book a flight
+
+ If no flights found, just say
+ no availablity for requested dates
+
+ **OUTPUT FORMAT:**
+ Provide 2-3 flight options as a bulleted list
+ (sorted by price in ascending order) with
+ - Airline name
+ - Departure and arrival times
+ - Price range
+ - Flight duration
+outputKey: flight_options
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/itinerary-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/itinerary-agent.yaml
new file mode 100644
index 000000000..0a5c0c094
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/itinerary-agent.yaml
@@ -0,0 +1,31 @@
+name: ItineraryAgent
+model: gemini-2.5-flash
+description: An itinerary builder for travelers
+instruction: |
+ **ROLE:**
+ You are a travel planner.
+
+ **GOAL:**
+ Create a complete, well-organized itinerary
+ by combining the search results below
+
+ **Available Flights:**
+ {flight_options?}
+
+ **Available Accomodations:**
+ {accomodation_options?}
+
+ **Recommended Activities:**
+ {activity_options?}
+
+ **Recommended Dining:**
+ {dining_options?}
+
+ **OUTPUT FORMAT:**
+ - Recommend the TOP option from each category (flights, hotel)
+ - Organize activities into a day-to-day plan
+ - Include estimated total cost
+ - Add helpful travel tips
+ Do not show intermediate steps.
+ Output ONLY the final itinerary
+outputKey: final_itinerary
\ No newline at end of file
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/prompt-day-in-rome.md b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/prompt-day-in-rome.md
new file mode 100644
index 000000000..05bd93f70
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/prompt-day-in-rome.md
@@ -0,0 +1,57 @@
+# PROMPT
+plan one day trip for a solo adult end of May with flexible dates
+- departure: Paris, France
+- destination: Rome, Italy.
+- travel dates: flexible dates end of May 2026 (e.g. May 29 - June 1, 2026)
+- flight preferences: none
+- activity preferences: history, museums, galleries, cathedrals, castles.
+- dining preferences: good Italian food
+
+
+# One-Day Rome Itinerary: Ancient Wonders & Iconic Fountains
+- For: Solo Adult
+- From: Paris, France
+- To: Rome, Italy
+- Date: End of May 2026 (e.g., May 30th)
+
+## Recommended Flights
+### Top Option:
+An early morning flight from Paris (CDG/ORY) to Rome (FCO) and a late evening return flight.
+- Airline: Air France (or Eurowings)
+- Departure and arrival times: Early morning departure (e.g., around 06:10 AM from Paris Charles de Gaulle) arriving mid-morning (e.g., around 08:10 AM in Rome Fiumicino). Late evening return (e.g., 9:00 PM - 9:30 PM from Rome Fiumicino) arriving late evening (e.g., 11:00 PM - 11:30 PM in Paris Charles de Gaulle).
+- Price range: ~$188 - €200 (round trip)
+- Flight duration: Approximately 2 hours - 2 hours 15 minutes per leg.
+
+Please note that these are estimated prices and times for a one-day trip at the end of May 2026, and actual availability and pricing may vary depending on the specific dates you choose and how far in advance you book.
+
+## Recommended Accommodations
+As this is a one-day trip, no overnight accommodation is needed. If you prefer a place to freshen up or store luggage, consider a day-use hotel near Termini Station or a luggage storage service.
+
+## Day-to-Day Plan: Rome in a Day
+### Morning: Ancient Rome (8:30 AM - 1:00 PM)
+
+- 8:30 AM - 9:00 AM: Arrive at Rome Fiumicino Airport (FCO), take the Leonardo Express train to Termini Station (approx. 32 minutes). Store any small luggage at Termini if needed.
+- 9:00 AM - 9:30 AM: Take the Metro (Line B) from Termini to Colosseo station.
+- 9:30 AM - 11:30 AM: Colosseum & Roman Forum. Marvel at the iconic Colosseum from the outside (consider booking a skip-the-line ticket in advance if you wish to enter, but for a one-day trip, viewing from outside and exploring the surrounding area might be more time-efficient). Walk through the Roman Forum and Palatine - Hill area, imagining ancient Roman life.
+- 11:30 AM - 1:00 PM: Walk towards the Pantheon. Enjoy the impressive architecture of this ancient Roman temple, now a church.
+
+### Lunch & Afternoon: Baroque Beauty (1:00 PM - 5:00 PM)
+
+- 1:00 PM - 2:00 PM: Lunch near the Pantheon. Grab a quick, authentic Roman pizza slice or a pasta dish at a local trattoria.
+- 2:00 PM - 3:00 PM: Walk to the Trevi Fountain. Toss a coin over your shoulder to ensure your return to Rome! Be prepared for crowds.
+- 3:00 PM - 4:00 PM: Stroll to the Spanish Steps (Piazza di Spagna). Climb the steps for a view, or simply enjoy the atmosphere at the base.
+- 4:00 PM - 5:00 PM: Wander through Piazza Navona, admiring Bernini's Fountain of Four Rivers and the lively street artists. Enjoy a gelato!
+
+### Late Afternoon/Evening: Last Bites & Departure (5:00 PM - 9:00 PM)
+
+- 5:00 PM - 6:30 PM: Enjoy some free time for souvenir shopping or a final coffee/aperitivo near Piazza Navona or Campo de' Fiori.
+- 6:30 PM - 7:30 PM: Early Dinner. Indulge in a final Roman meal – perhaps Cacio e Pepe or Carbonara – near Termini Station for convenience.
+- 7:30 PM - 8:00 PM: Head back to Termini Station.
+- 8:00 PM - 8:30 PM: Take the Leonardo Express back to Fiumicino Airport (FCO).
+- 9:00 PM: Depart from Rome Fiumicino Airport (FCO).
+
+## Estimated Total Cost (Not based on actual search results)
+- Flights (Round-trip Paris-Rome): €100 - €250 (highly variable depending on booking time, airline, and flexibility)
+- Airport Transfer (Leonardo Express x2): €14 x 2 = €28
+- Local Transport (Metro/Bus): €7 (e.g., 2-3 single tickets or a 24-hour pass)
+- Food & Drink: €40 - €70 (Lunch, dinner, gelato, coffee/water)
diff --git a/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/root-agent.yaml b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/root-agent.yaml
new file mode 100644
index 000000000..4d5077985
--- /dev/null
+++ b/contrib/multi-agent-patterns/src/main/resources/agent-configs/traveler/root-agent.yaml
@@ -0,0 +1,17 @@
+name: TravelerRootAgent
+model: gemini-2.5-flash
+description: Personalized and professional Travel Advisor
+instruction: |
+ **ROLE:**
+ You are a Travel Planner Agent
+ Act as a personalized, professional
+ travel assistant, providing tailored,
+ in-depth travel itineraries
+
+ **INFORMATION GATHERING:**
+ Proactively ask for destination, dates,
+ budget, travel style, and group size.
+
+ Delegate the search and itinerary requests to TripAssistantWorkflow agent
+ Do not conduct any search youself.
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 6f6837df5..4784230b0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,6 +33,7 @@
contrib/samples
contrib/planners
contrib/firestore-session-service
+ contrib/multi-agent-patterns
tutorials/city-time-weather
tutorials/live-audio-single-agent
a2a