fix: allow custom agent scaffolds
All checks were successful
build / build (push) Successful in 27s

This commit is contained in:
robert
2026-05-17 19:12:58 -03:00
parent 2a6227b8ec
commit 1f3f8349df
3 changed files with 4 additions and 100 deletions

View File

@@ -4,8 +4,6 @@ WORKDIR /app
COPY requirements.txt . COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
RUN python -c "import importlib.resources as r, a2a_pack; t = r.files('a2a_pack.cli.templates').joinpath('agent.py.tmpl').read_text(); missing = [m for m in ('LLMProvisioning.CALLER_PROVIDED', 'ctx.llm', 'ctx.workspace_backend()', 'create_deep_agent', 'wrap_model_call') if m not in t]; assert not missing, f'a2a-pack {a2a_pack.__version__} has stale init template; missing {missing}'"
COPY . . COPY . .
ENV A2A_ENTRYPOINT=agent:AgentBuilder ENV A2A_ENTRYPOINT=agent:AgentBuilder

View File

@@ -213,16 +213,6 @@ def build_tools(ctx: ToolContext) -> list[Any]:
return json.dumps({ return json.dumps({
"error": "no files in agents/" + name + "/ — write some first", "error": "no files in agents/" + name + "/ — write some first",
}) })
try:
_assert_current_agent_project(bundle_bytes)
except RuntimeError as exc:
return json.dumps({
"error": str(exc),
"hint": (
"Call init_agent_template first, then edit the generated "
"DeepAgents files instead of replacing agent.py from memory."
),
})
b64 = base64.b64encode(bundle_bytes).decode("ascii") b64 = base64.b64encode(bundle_bytes).decode("ascii")
script = ( script = (
"set -e\n" "set -e\n"
@@ -289,17 +279,6 @@ def build_tools(ctx: ToolContext) -> list[Any]:
bundle_bytes = _tarball_workspace_dir(s3, bucket, prefix) bundle_bytes = _tarball_workspace_dir(s3, bucket, prefix)
if not bundle_bytes: if not bundle_bytes:
return json.dumps({"error": f"no files at agents/{name}/"}) return json.dumps({"error": f"no files at agents/{name}/"})
try:
_assert_current_agent_project(bundle_bytes)
except RuntimeError as exc:
return json.dumps({
"error": str(exc),
"hint": (
"Run init_agent_template again or restore the generated "
"DeepAgents scaffold before deploying."
),
})
# Read the entrypoint from a2a.yaml so we can pass it verbatim. # Read the entrypoint from a2a.yaml so we can pass it verbatim.
entrypoint = _read_entrypoint(bundle_bytes) or f"agent:{_class_name(name)}" entrypoint = _read_entrypoint(bundle_bytes) or f"agent:{_class_name(name)}"
@@ -542,18 +521,6 @@ def _read_bundle_text(bundle: bytes, path: str) -> str | None:
return None return None
def _assert_current_agent_project(bundle: bytes) -> None:
files = {
path: text
for path in ("agent.py", "requirements.txt")
if (text := _read_bundle_text(bundle, path)) is not None
}
_assert_current_deepagents_scaffold(
files,
source="agent project",
)
def _class_name(slug: str) -> str: def _class_name(slug: str) -> str:
return "".join(p.capitalize() for p in re.split(r"[-_]+", slug) if p) or "MyAgent" return "".join(p.capitalize() for p in re.split(r"[-_]+", slug) if p) or "MyAgent"
@@ -579,58 +546,9 @@ def _render_a2a_init_template(
), ),
"requirements.txt": _render_sdk_template("requirements.txt.tmpl"), "requirements.txt": _render_sdk_template("requirements.txt.tmpl"),
} }
_assert_current_a2a_init_template(files)
return files return files
def _assert_current_a2a_init_template(files: dict[str, str]) -> None:
_assert_current_deepagents_scaffold(
files,
source="installed a2a-pack init template",
)
def _assert_current_deepagents_scaffold(
files: dict[str, str],
*,
source: str,
) -> None:
required_markers = {
"agent.py": (
"LLMProvisioning.CALLER_PROVIDED",
"ctx.llm",
"ctx.workspace_backend()",
"create_deep_agent",
"wrap_model_call",
"ChatOpenAI",
),
"requirements.txt": (
"deepagents>=0.5.0",
"langchain-openai",
),
}
missing: list[str] = []
for path, markers in required_markers.items():
content = files.get(path, "")
for marker in markers:
if marker not in content:
missing.append(f"{path}:{marker}")
if not missing:
return
try:
import a2a_pack
version = getattr(a2a_pack, "__version__", "unknown")
except Exception: # noqa: BLE001
version = "unknown"
raise RuntimeError(
f"{source} is stale; expected the 0.1.4+ "
"DeepAgents caller-LLM scaffold. "
f"a2a_pack={version}; missing markers: {', '.join(missing)}"
)
def _render_sdk_template(template: str, /, **vars: str) -> str: def _render_sdk_template(template: str, /, **vars: str) -> str:
text = ( text = (
resources.files("a2a_pack.cli.templates") resources.files("a2a_pack.cli.templates")

View File

@@ -5,8 +5,6 @@ import tarfile
import unittest import unittest
from agent_builder.tools import ( from agent_builder.tools import (
_assert_current_agent_project,
_assert_current_a2a_init_template,
_render_a2a_init_template, _render_a2a_init_template,
) )
@@ -33,21 +31,11 @@ class TemplateInitTests(unittest.TestCase):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
_render_a2a_init_template("Bad Name") _render_a2a_init_template("Bad Name")
def test_stale_sdk_template_is_rejected(self) -> None: def test_agent_projects_can_diverge_from_template(self) -> None:
with self.assertRaisesRegex(RuntimeError, "stale"): files = _render_a2a_init_template("regex-explainer")
_assert_current_a2a_init_template({ files["agent.py"] = "from a2a_pack import A2AAgent\n"
"agent.py": "from a2a_pack import A2AAgent",
"requirements.txt": "httpx>=0.27",
})
def test_stale_agent_project_is_rejected(self) -> None: self.assertIn("A2AAgent", files["agent.py"])
bundle = _tarball({
"agent.py": "from a2a_pack import A2AAgent\n",
"requirements.txt": "httpx>=0.27\n",
})
with self.assertRaisesRegex(RuntimeError, "agent project is stale"):
_assert_current_agent_project(bundle)
def _tarball(files: dict[str, str]) -> bytes: def _tarball(files: dict[str, str]) -> bytes: