-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat: add a2a agent card generation with the CLI #3606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e49c692
291a473
6051de6
921a203
0e97442
3141abc
6044144
3557f02
2d49d1d
67a6739
b06f74d
d0a7b90
5fa7105
7fe4931
10202f1
c1de9a7
191a5ea
d9dcce1
b5ef552
9c65fdc
8e56456
803c9cb
14042c6
294781f
ee4d6ce
2c57fca
1965b30
ebdc00c
ca03f5f
abc3d80
d42a74d
a15267f
308734e
30ee45d
a0fad41
cbb1842
9b8108a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| # Copyright 2025 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| from __future__ import annotations | ||
|
|
||
| import asyncio | ||
| import json | ||
| import os | ||
|
|
||
| import click | ||
|
|
||
| from .utils.agent_loader import AgentLoader | ||
|
|
||
|
|
||
| @click.command(name="generate_agent_card") | ||
| @click.option( | ||
| "--protocol", | ||
| default="https", | ||
| help="Protocol for the agent URL (default: https)", | ||
| ) | ||
| @click.option( | ||
| "--host", | ||
| default="127.0.0.1", | ||
| help="Host for the agent URL (default: 127.0.0.1)", | ||
| ) | ||
| @click.option( | ||
| "--port", | ||
| default="8000", | ||
| help="Port for the agent URL (default: 8000)", | ||
| ) | ||
| @click.option( | ||
| "--create-file", | ||
| is_flag=True, | ||
| default=False, | ||
| help="Create agent.json file in each agent directory", | ||
| ) | ||
| def generate_agent_card( | ||
| protocol: str, host: str, port: str, create_file: bool | ||
| ) -> None: | ||
| """Generates agent cards for all detected agents.""" | ||
| asyncio.run(_generate_agent_card_async(protocol, host, port, create_file)) | ||
|
|
||
|
|
||
| async def _generate_agent_card_async( | ||
| protocol: str, host: str, port: str, create_file: bool | ||
| ) -> None: | ||
| try: | ||
| from ..a2a.utils.agent_card_builder import AgentCardBuilder | ||
| except ImportError: | ||
| click.secho( | ||
| "Error: 'a2a' package is required for this command. " | ||
| "Please install it with 'pip install google-adk[a2a]'.", | ||
| fg="red", | ||
| err=True, | ||
| ) | ||
| raise click.Abort() | ||
|
|
||
| cwd = os.getcwd() | ||
| loader = AgentLoader(agents_dir=cwd) | ||
| agent_names = loader.list_agents() | ||
| agent_cards = [] | ||
|
|
||
| for agent_name in agent_names: | ||
| try: | ||
| agent = loader.load_agent(agent_name) | ||
| # If it's an App, get the root agent | ||
| if hasattr(agent, "root_agent"): | ||
| agent = agent.root_agent | ||
| builder = AgentCardBuilder( | ||
| agent=agent, | ||
| rpc_url=f"{protocol}://{host}:{port}/{agent_name}", | ||
| ) | ||
| card = await builder.build() | ||
| card_dict = card.model_dump(exclude_none=True) | ||
| agent_cards.append(card_dict) | ||
|
|
||
| if create_file: | ||
| agent_dir = os.path.join(cwd, agent_name) | ||
| agent_json_path = os.path.join(agent_dir, "agent.json") | ||
| with open(agent_json_path, "w", encoding="utf-8") as f: | ||
| json.dump(card_dict, f, indent=2) | ||
|
Comment on lines
+88
to
+91
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider using |
||
| except Exception as e: | ||
| # Log error but continue with other agents | ||
| # Using click.echo to print to stderr to not mess up JSON output on stdout | ||
| click.echo(f"Error processing agent {agent_name}: {e}", err=True) | ||
|
|
||
| click.echo(json.dumps(agent_cards, indent=2)) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
portparameter is currently a string. It would be more robust to define it as an integer. You can achieve this by settingtype=intanddefault=8000in the@click.optionfor--port. Remember to also update the type hints forporttointin thegenerate_agent_cardand_generate_agent_card_asyncfunction signatures.