This commit is contained in:
@@ -213,6 +213,16 @@ 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"
|
||||||
@@ -279,6 +289,16 @@ 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)}"
|
||||||
@@ -508,6 +528,32 @@ def _read_entrypoint(bundle: bytes) -> str | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _read_bundle_text(bundle: bytes, path: str) -> str | None:
|
||||||
|
try:
|
||||||
|
with tarfile.open(fileobj=io.BytesIO(bundle), mode="r:gz") as tf:
|
||||||
|
for member in tf.getmembers():
|
||||||
|
if member.name == path and member.isfile():
|
||||||
|
extracted = tf.extractfile(member)
|
||||||
|
if extracted is None:
|
||||||
|
return None
|
||||||
|
return extracted.read().decode("utf-8", "replace")
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
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"
|
||||||
|
|
||||||
@@ -538,6 +584,17 @@ def _render_a2a_init_template(
|
|||||||
|
|
||||||
|
|
||||||
def _assert_current_a2a_init_template(files: dict[str, str]) -> None:
|
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 = {
|
required_markers = {
|
||||||
"agent.py": (
|
"agent.py": (
|
||||||
"LLMProvisioning.CALLER_PROVIDED",
|
"LLMProvisioning.CALLER_PROVIDED",
|
||||||
@@ -567,7 +624,7 @@ def _assert_current_a2a_init_template(files: dict[str, str]) -> None:
|
|||||||
except Exception: # noqa: BLE001
|
except Exception: # noqa: BLE001
|
||||||
version = "unknown"
|
version = "unknown"
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"installed a2a-pack init template is stale; expected the 0.1.3+ "
|
f"{source} is stale; expected the 0.1.3+ "
|
||||||
"DeepAgents caller-LLM scaffold. "
|
"DeepAgents caller-LLM scaffold. "
|
||||||
f"a2a_pack={version}; missing markers: {', '.join(missing)}"
|
f"a2a_pack={version}; missing markers: {', '.join(missing)}"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import io
|
||||||
|
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,
|
_assert_current_a2a_init_template,
|
||||||
_render_a2a_init_template,
|
_render_a2a_init_template,
|
||||||
)
|
)
|
||||||
@@ -35,3 +38,23 @@ class TemplateInitTests(unittest.TestCase):
|
|||||||
"agent.py": "from a2a_pack import A2AAgent",
|
"agent.py": "from a2a_pack import A2AAgent",
|
||||||
"requirements.txt": "httpx>=0.27",
|
"requirements.txt": "httpx>=0.27",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def test_stale_agent_project_is_rejected(self) -> None:
|
||||||
|
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:
|
||||||
|
buf = io.BytesIO()
|
||||||
|
with tarfile.open(fileobj=buf, mode="w:gz") as tf:
|
||||||
|
for path, text in files.items():
|
||||||
|
body = text.encode("utf-8")
|
||||||
|
info = tarfile.TarInfo(path)
|
||||||
|
info.size = len(body)
|
||||||
|
tf.addfile(info, io.BytesIO(body))
|
||||||
|
return buf.getvalue()
|
||||||
|
|||||||
Reference in New Issue
Block a user