Skip to content

feat: add AG2 multi-agent framework template#917

Open
faridun-ag2 wants to merge 3 commits intoGoogleCloudPlatform:mainfrom
faridun-ag2:faridunm/add-ag2-template
Open

feat: add AG2 multi-agent framework template#917
faridun-ag2 wants to merge 3 commits intoGoogleCloudPlatform:mainfrom
faridun-ag2:faridunm/add-ag2-template

Conversation

@faridun-ag2
Copy link
Copy Markdown

Summary

  • Adds AG2 (formerly AutoGen) as a new agent template
  • Supports cloud_run and none deployment targets
  • Includes tool use example with decorator-based registration
  • Supports Vertex AI (Gemini) and Google API key backends

Problem

The starter pack supports ADK and LangGraph but has no multi-agent framework template. AG2 is one of the most popular multi-agent frameworks (500K+ monthly PyPI downloads, 4,300+ GitHub stars) and fills this gap.

Solution

New ag2 agent template following the existing template structure:

  • app/agent.py — Core agent with tool use via AG2's decorator pattern
  • notebooks/getting_started.ipynb — Basic usage, custom tools, and GroupChat
  • tests/integration/test_agent.py — Tool tests and agent integration tests
  • .template/templateconfig.yaml — Template config for cloud_run and none targets

Jinja integration in existing templates:

  • fast_api_app.py — AG2 branch with /query and /health endpoints
  • typing.py, telemetry.py — AG2 branches without LangChain dependencies
  • test_server_e2e.py, load_test.py — AG2-specific test and load patterns
  • Makefile — AG2 playground for none deployment target

Testing

  • make lint passes
  • make test passes (495 passed, 3 skipped)
  • AG2 + cloud_run template: codespell, ruff, ruff format, ty — all pass
  • AG2 + none template: codespell, ruff, ruff format, ty — all pass
  • E2E manual test: server starts, /query returns correct tool-use response

Add AG2 (formerly AutoGen) as a new agent template with cloud_run and
none deployment targets. AG2 is an open-source multi-agent framework
with 500K+ monthly PyPI downloads.

New template includes:
- app/agent.py with tool use via AG2's decorator pattern
- Vertex AI (Gemini) by default, Google API key fallback
- FastAPI serving layer with /query and /health endpoints
- Getting started notebook with GroupChat example
- Integration tests for tool and agent execution

Jinja integration touches:
- fast_api_app.py — AG2 branch with simple query endpoint
- typing.py, telemetry.py — AG2 branches without LangChain deps
- test_server_e2e.py, load_test.py — AG2 test/load patterns
- Makefile — playground for none deployment
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Mar 31, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@faridun-ag2
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new multi-agent template powered by the AG2 framework, providing a core agent implementation with tool support, a tutorial notebook, and deployment scaffolding for Cloud Run and GKE. The reviewer identified several critical bugs in app/agent.py and the tutorial notebook, specifically the use of non-existent process() and messages attributes on the ChatResult object, which will cause runtime errors. Additionally, typos in the Gemini model names were noted, and a suggestion was made to include the gemini extra in the notebook's dependency installation.

Comment on lines +103 to +104
response = user_proxy.run(assistant, message=message)
response.process()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The ChatResult object returned by agent.run() (or initiate_chat) does not have a process() method. This line will cause an AttributeError at runtime. The result is already populated and ready for use.

    response = user_proxy.run(assistant, message=message)

if response.summary:
return response.summary.replace("TERMINATE", "").strip()

for msg in reversed(response.messages):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The ChatResult object uses the attribute chat_history to store the conversation log, not messages. This will cause an AttributeError.

    for msg in reversed(response.chat_history):


llm_config = LLMConfig(
{
"model": "gemini-2.5-flash",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The model name gemini-2.5-flash appears to be a typo. As of now, the available stable versions are gemini-1.5-flash or gemini-2.0-flash.

        "model": "gemini-1.5-flash",


llm_config = LLMConfig(
{
"model": "gemini-2.5-flash",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The model name gemini-2.5-flash appears to be a typo. As of now, the available stable versions are gemini-1.5-flash or gemini-2.0-flash.

        "model": "gemini-1.5-flash",

"metadata": {},
"outputs": [],
"source": [
"%pip install \"ag2[openai]>=0.11.4,<1.0\" python-dotenv -q"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since the template defaults to using Gemini (Vertex AI), the gemini extra should be included in the installation command to ensure all necessary dependencies are present.

Suggested change
"%pip install \"ag2[openai]>=0.11.4,<1.0\" python-dotenv -q"
"%pip install \"ag2[openai,gemini]>=0.11.4,<1.0\" python-dotenv -q"

"def square(n: Annotated[int, \"The number to square\"]) -> int:\n",
" return n * n\n",
"\n",
"result = user_proxy.run(assistant, message=\"What is 42 squared?\").process()"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

As noted in the main agent implementation, ChatResult does not have a process() method. This will cause the notebook cell to fail.

Suggested change
"result = user_proxy.run(assistant, message=\"What is 42 squared?\").process()"
"result = user_proxy.run(assistant, message=\"What is 42 squared?\")"

"result = coordinator.run(\n",
" manager,\n",
" message=\"Write a brief overview of how AI is used in weather forecasting.\",\n",
").process()"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The .process() method is not available on the ChatResult object returned by the agent execution.

    )"

- Remove unnecessary process() call from run_agent() — result is
  already available on the RunResponse object
- Add gemini extra to notebook pip install command
- Remove .process() calls from notebook code cells
@faridun-ag2
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new multi-agent template based on the AG2 framework, providing a complete implementation with tool use, FastAPI endpoints for deployment on Cloud Run and GKE, and comprehensive integration tests. The review feedback identifies critical issues in agent.py regarding the incorrect instantiation of LLMConfig and the use of an invalid model name. Furthermore, it suggests improving code quality by replacing file-wide linting suppressions with targeted ones and ensuring consistent use of the module-level logger in the FastAPI application files.

Comment on lines +34 to +41
llm_config = LLMConfig(
{
"model": "gemini-2.5-flash",
"api_type": "google",
"project_id": os.environ["GOOGLE_CLOUD_PROJECT"],
"location": os.environ["GOOGLE_CLOUD_LOCATION"],
}
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The LLMConfig instantiation is incorrect and uses an invalid model name. In ag2, LLMConfig expects a config_list (a list of dictionaries) rather than a single dictionary. Additionally, gemini-2.5-flash is not a valid model name; it should be gemini-2.0-flash or gemini-1.5-flash.

llm_config = LLMConfig(
    config_list=[
        {
            "model": "gemini-2.0-flash",
            "api_type": "google",
            "project_id": os.environ["GOOGLE_CLOUD_PROJECT"],
            "location": os.environ["GOOGLE_CLOUD_LOCATION"],
        }
    ]
)

Comment on lines +44 to +50
llm_config = LLMConfig(
{
"model": "gemini-2.5-flash",
"api_key": os.environ.get("GOOGLE_API_KEY", ""),
"api_type": "google",
}
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The LLMConfig instantiation for the Google API key backend should also use the config_list parameter and a valid model name.

llm_config = LLMConfig(
    config_list=[
        {
            "model": "gemini-2.0-flash",
            "api_key": os.environ.get("GOOGLE_API_KEY", ""),
            "api_type": "google",
        }
    ]
)

@@ -0,0 +1,119 @@
# ruff: noqa
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using # ruff: noqa to disable all linting for the entire file is discouraged. It is better to address specific linting issues or use targeted suppressions if Jinja syntax causes false positives during template linting. This ensures the template follows the project's code quality standards.

References
  1. The project uses ruff for Python linting to maintain code quality. (link)

@app.post("/query", response_model=QueryResponse)
def query(request: QueryRequest) -> QueryResponse:
"""Run the AG2 agent with the given message."""
logging.info(f"Received query: {request.message}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Use the module-level logger instead of the global logging module for consistency and to ensure logs are correctly handled by the configured logging system.

    logger.info(f"Received query: {request.message}")
References
  1. Follow established patterns and replicate existing conventions for naming and logic. (link)

@app.post("/query", response_model=QueryResponse)
def query(request: QueryRequest) -> QueryResponse:
"""Run the AG2 agent with the given message."""
logging.info(f"Received query: {request.message}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Use the module-level logger instead of the global logging module for consistency.

    logger.info(f"Received query: {request.message}")
References
  1. Follow established patterns and replicate existing conventions for naming and logic. (link)

- Use module-level logger instead of logging.info in fast_api_app.py
  (cloud_run and gke)
- Fix ty type-check error: wrap response.messages in list() for
  reversed() compatibility

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@faridun-ag2
Copy link
Copy Markdown
Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new multi-agent template based on the AG2 framework, including core implementation, integration tests, and deployment configurations for Cloud Run and GKE. The review feedback correctly identifies typos in the Gemini model versions and a potential AttributeError in the response processing logic. Furthermore, the reviewer suggests improving telemetry and unifying logging practices to maintain consistency with existing templates and established repository patterns.


llm_config = LLMConfig(
{
"model": "gemini-2.5-flash",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The model name gemini-2.5-flash appears to be a typo, as Gemini 2.5 has not been released. It should likely be gemini-1.5-flash or gemini-2.0-flash.

        "model": "gemini-1.5-flash",


llm_config = LLMConfig(
{
"model": "gemini-2.5-flash",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The model name gemini-2.5-flash appears to be a typo, as Gemini 2.5 has not been released. It should likely be gemini-1.5-flash or gemini-2.0-flash.

        "model": "gemini-1.5-flash",

if response.summary:
return response.summary.replace("TERMINATE", "").strip()

for msg in reversed(list(response.messages)):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The ChatResult object returned by user_proxy.run() in AG2/AutoGen uses the chat_history attribute to store the conversation history. The attribute messages is not standard in version 0.11.4 and will likely cause an AttributeError.

    for msg in reversed(response.chat_history):

Comment on lines +92 to +99
def setup_telemetry() -> str | None:
"""Configure telemetry for AG2 agents."""
bucket = os.environ.get("LOGS_BUCKET_NAME")
if bucket:
logger.info("Telemetry bucket configured: %s", bucket)
else:
logger.info("No telemetry bucket configured")
return bucket
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The setup_telemetry implementation for AG2 is very minimal compared to other agent templates (like LangGraph or ADK), which include OpenTelemetry tracing and Cloud Logging integration. To maintain feature parity and provide a better production-ready experience, consider implementing a more robust telemetry setup for AG2 agents.

Comment on lines +607 to +611
{%- if cookiecutter.get("agent_name") == "ag2" %}
logger.info("Feedback received: %s", feedback.model_dump())
{%- else %}
logger.log_struct(feedback.model_dump(), severity="INFO")
{%- endif %}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logging approach for ag2 is inconsistent with other agents in this file. While other agents use logger.log_struct for structured logging in Google Cloud, ag2 uses standard logger.info. It is recommended to unify the logger initialization (using google.cloud.logging) and usage across all agent types to ensure consistent log formatting and better observability in Cloud Logging.

Comment on lines +607 to +611
{%- if cookiecutter.get("agent_name") == "ag2" %}
logger.info("Feedback received: %s", feedback.model_dump())
{%- else %}
logger.log_struct(feedback.model_dump(), severity="INFO")
{%- endif %}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logging approach for ag2 is inconsistent with other agents in this file. While other agents use logger.log_struct for structured logging in Google Cloud, ag2 uses standard logger.info. It is recommended to unify the logger initialization (using google.cloud.logging) and usage across all agent types to ensure consistent log formatting and better observability in Cloud Logging.

@faridun-ag2
Copy link
Copy Markdown
Author

Hello @eliasecchig @elia-secchi!
I would appreciate your review on this PR when you have a moment.

Note on Gemini Code Assist review comments

The automated Gemini reviewer flagged several issues that are incorrect due to outdated knowledge of the AG2 and Gemini APIs. Wanted to call these out to save you time:

1. gemini-2.5-flash "doesn't exist" (marked critical)
The model exists and works. We verified this with a successful E2E test — the agent calls the Gemini API, invokes the get_weather tool, and returns the correct response. Gemini Code Assist's training data predates this model release.

2. response.messages should be response.chat_history (marked critical)
In AG2 v0.11.4, user_proxy.run() returns a RunResponse object (not ChatResult). We verified via inspect.signature() that RunResponse has .messages and .summary attributes. The old ChatResult.chat_history pattern is from a previous AG2 version.

3. LLMConfig should use config_list= keyword (marked high)
In AG2 v0.11.4, LLMConfig.__init__ accepts *configs as positional arguments. Passing a dict positionally is the correct pattern and passes ty type checking.

Feedback that was addressed

  • ✅ Removed unnecessary process() calls from agent.py and notebook
  • ✅ Added gemini extra to notebook pip install
  • ✅ Changed logging.infologger.info for consistency
  • ✅ Fixed ty type-check error with reversed()

Intentional design decisions

  • Minimal telemetry: Kept simple for the initial template — can be enhanced in a follow-up
  • logger.info in feedback endpoint: AG2 template uses standard Python logging with a graceful fallback when GCP credentials aren't available (for local development with Google API key)
  • # ruff: noqa in agent.py: Same pattern used by the existing langgraph/app/agent.py — needed because Jinja syntax breaks ruff's Python parser

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant