feat: initialize agents from a2a template
All checks were successful
build / build (push) Successful in 2s

This commit is contained in:
robert
2026-05-16 17:35:05 -03:00
parent 137847bab1
commit 1bb6044b15
3 changed files with 102 additions and 3 deletions

View File

@@ -84,6 +84,11 @@ when you deploy through the control plane).
Your tools:
- init_agent_template(name, description)
— initialize agents/<name>/ from the
installed a2a-pack `a2a init` template.
Use this FIRST for a new project, then
edit the generated files.
- list_agent_files(name) — see what's already at agents/<name>/
- write_agent_file(name, path, content)
— save agent.py / a2a.yaml / requirements.txt
@@ -116,8 +121,10 @@ Discipline:
- Pick a kebab-case slug for ``name`` (e.g. ``research-agent``,
``csv-sanitizer``). Class name is PascalCase from the slug.
- Write ALL THREE files (agent.py, a2a.yaml, requirements.txt) before
testing — partial scaffolds break ``a2a card``.
- For a new project, call init_agent_template first. Then read/edit the
generated files instead of inventing boilerplate from memory.
- Ensure all three core files (agent.py, a2a.yaml, requirements.txt)
exist before testing — partial scaffolds break ``a2a card``.
- Always run test_agent_in_sandbox before deploying. If exit_code != 0,
read stderr, edit the offending file, retest. Do NOT deploy a broken
scaffold.

View File

@@ -14,6 +14,7 @@ import re
import tarfile
import time
from dataclasses import dataclass
from importlib import resources
from typing import TYPE_CHECKING, Any
import boto3
@@ -111,6 +112,36 @@ def build_tools(ctx: ToolContext) -> list[Any]:
s3 = _s3(ctx)
_ensure_bucket(s3, bucket)
@tool
def init_agent_template(
name: str,
description: str = "A new A2A agent",
) -> str:
"""Initialize ``agents/<name>/`` from the installed a2a-pack template.
Use this FIRST for a new project. It writes the same baseline files
as ``a2a init`` for the SDK version installed in this runtime:
``agent.py``, ``a2a.yaml``, and ``requirements.txt``. After this,
edit those files with ``read_agent_file`` + ``write_agent_file`` to
implement the user's requested behavior.
"""
try:
files = _render_a2a_init_template(name, description=description)
prefix = _agent_prefix(name)
except (OSError, ValueError) as exc:
return json.dumps({"error": str(exc)})
written: list[dict[str, Any]] = []
for path, content in files.items():
key = prefix + path
s3.put_object(
Bucket=bucket,
Key=key,
Body=content.encode("utf-8"),
ContentType="text/plain; charset=utf-8",
)
written.append({"path": key, "size": len(content)})
return json.dumps({"ok": True, "agent": name, "files": written})
@tool
def list_agent_files(name: str) -> str:
"""List every file under ``agents/<name>/`` in the user's workspace.
@@ -434,7 +465,7 @@ def build_tools(ctx: ToolContext) -> list[Any]:
})
return [
list_agent_files, write_agent_file, read_agent_file,
init_agent_template, list_agent_files, write_agent_file, read_agent_file,
test_agent_in_sandbox, cp_deploy_tarball, cp_refresh_agent,
list_a2a_pack, read_a2a_pack,
]
@@ -479,3 +510,37 @@ def _read_entrypoint(bundle: bytes) -> str | None:
def _class_name(slug: str) -> str:
return "".join(p.capitalize() for p in re.split(r"[-_]+", slug) if p) or "MyAgent"
def _render_a2a_init_template(
name: str,
*,
description: str = "A new A2A agent",
) -> dict[str, str]:
_validate_name(name)
class_name = _class_name(name)
return {
"agent.py": _render_sdk_template(
"agent.py.tmpl",
name=name,
class_name=class_name,
description=description,
),
"a2a.yaml": _render_sdk_template(
"a2a.yaml.tmpl",
name=name,
class_name=class_name,
),
"requirements.txt": _render_sdk_template("requirements.txt.tmpl"),
}
def _render_sdk_template(template: str, /, **vars: str) -> str:
text = (
resources.files("a2a_pack.cli.templates")
.joinpath(template)
.read_text(encoding="utf-8")
)
for key, value in vars.items():
text = text.replace("{{ " + key + " }}", value)
return text