fix: align agent-builder with longer pack timeouts
All checks were successful
build / build (push) Successful in 27s

This commit is contained in:
robert
2026-05-20 19:41:22 -03:00
parent 4c8cd8ab2f
commit 1411a445e1
6 changed files with 37 additions and 4 deletions

View File

@@ -17,8 +17,10 @@ because it needs three things forwarded from the caller:
"""
from __future__ import annotations
import asyncio
import json
import re
from contextlib import suppress
from typing import Any
from pydantic import BaseModel
@@ -65,6 +67,7 @@ class AgentBuilder(A2AAgent[BuilderConfig, NoAuth]):
"should do. Returns the live URL when ready."
),
tags=["builder", "scaffold", "deepagents", "meta"],
stream=True,
)
async def build(
self,
@@ -127,6 +130,13 @@ class AgentBuilder(A2AAgent[BuilderConfig, NoAuth]):
final_state: dict[str, Any] = {}
deployed_url: str | None = None
last_reply: str = ""
async def _heartbeat() -> None:
while True:
await asyncio.sleep(20)
await ctx.emit_progress(f"agent-builder still working on {name!r}")
heartbeat_task = asyncio.create_task(_heartbeat())
try:
async for event in graph.astream_events(
{"messages": [{"role": "user", "content": user_msg}]},
@@ -156,6 +166,10 @@ class AgentBuilder(A2AAgent[BuilderConfig, NoAuth]):
final_state = out
except Exception as exc: # noqa: BLE001
return {"error": f"build graph failed: {type(exc).__name__}: {exc}"}
finally:
heartbeat_task.cancel()
with suppress(asyncio.CancelledError):
await heartbeat_task
for msg in final_state.get("messages") or []:
content = msg.get("content") if isinstance(msg, dict) else getattr(msg, "content", None)

View File

@@ -9,6 +9,7 @@ from dataclasses import dataclass
class Settings:
sandbox_url: str
sandbox_timeout_s: int
deploy_wait_timeout_s: int
litellm_url: str
litellm_key: str
litellm_model: str
@@ -24,7 +25,8 @@ def load_settings() -> Settings:
sandbox_url=os.environ.get(
"SANDBOX_URL", "http://sandbox.sandbox.svc.cluster.local:8000"
),
sandbox_timeout_s=int(os.environ.get("SANDBOX_TIMEOUT_S", "240")),
sandbox_timeout_s=int(os.environ.get("SANDBOX_TIMEOUT_S", "1200")),
deploy_wait_timeout_s=int(os.environ.get("DEPLOY_WAIT_TIMEOUT_S", "900")),
litellm_url=os.environ.get(
"A2A_LITELLM_URL", "http://litellm.llm.svc.cluster.local:4000"
),

View File

@@ -38,7 +38,7 @@ class ToolContext:
async def _wait_for_live_card(
url: str | None,
expected_version: str | None,
timeout_s: float = 180.0,
timeout_s: float = 900.0,
) -> tuple[bool, dict[str, Any]]:
"""Poll ``{url}/.well-known/agent-card`` until ``version`` matches
``expected_version`` or ``timeout_s`` elapses. Returns
@@ -435,7 +435,11 @@ def build_tools(ctx: ToolContext) -> list[Any]:
# so the LLM can verify the input_schema actually matches the
# code it wrote — catches the schema/code skew that causes
# downstream 400s on call_agent.
live, live_card = await _wait_for_live_card(url_, version_)
live, live_card = await _wait_for_live_card(
url_,
version_,
timeout_s=settings.deploy_wait_timeout_s,
)
out: dict[str, Any] = {
"ok": live,
"name": name_,

View File

@@ -32,6 +32,10 @@ spec:
value: registry.a2acloud.io/agents/agent-builder:f7da050814bf8856fb2df0949d8140b34d379864
- name: SANDBOX_URL
value: http://sandbox.sandbox.svc.cluster.local:8000
- name: SANDBOX_TIMEOUT_S
value: "1200"
- name: DEPLOY_WAIT_TIMEOUT_S
value: "900"
- name: A2A_LITELLM_URL
value: http://litellm.llm.svc.cluster.local:4000
- name: A2A_LITELLM_KEY

View File

@@ -1,4 +1,4 @@
a2a-pack>=0.1.12
a2a-pack>=0.1.14
httpx>=0.27
boto3>=1.34
deepagents>=0.5.0

View File

@@ -21,6 +21,15 @@ class BuilderPromptTests(unittest.TestCase):
"config={\"recursion_limit\": DEEPAGENTS_RECURSION_LIMIT}",
agent_source,
)
self.assertIn("stream=True", agent_source)
def test_builder_defaults_raise_timeout_budget(self) -> None:
config_source = Path(__file__).resolve().parents[1].joinpath(
"agent_builder/config.py"
).read_text()
self.assertIn('sandbox_timeout_s=int(os.environ.get("SANDBOX_TIMEOUT_S", "1200"))', config_source)
self.assertIn('deploy_wait_timeout_s=int(os.environ.get("DEPLOY_WAIT_TIMEOUT_S", "900"))', config_source)
def test_prompt_requires_resource_mirror_for_heavy_agents(self) -> None:
self.assertIn("declare resources in BOTH places", SYSTEM_PROMPT)