Add explicit source repo deploy tool
All checks were successful
build / build (push) Successful in 50s
All checks were successful
build / build (push) Successful in 50s
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
- workspace file CRUD through the caller's scoped workspace grant
|
||||
- sandbox python (for `a2a card` / `a2a validate` round-trips)
|
||||
- cp_deploy_tarball (call /v1/agents/from-tarball on the user's behalf)
|
||||
- cp_deploy_source_repo (call /v1/agents/{name}/source/deploy)
|
||||
- cp_compose_meta_agent (call /v1/agents/compose with a manifest)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
@@ -661,8 +662,10 @@ def build_tools(ctx: ToolContext) -> list[Any]:
|
||||
f"{settings.sandbox_url}/v1/run_shell",
|
||||
headers=headers,
|
||||
json={
|
||||
"bucket": bucket, "script": script,
|
||||
"image": settings.image, "memory_mib": 512,
|
||||
"bucket": bucket,
|
||||
"script": script,
|
||||
"image": settings.image,
|
||||
"memory_mib": 512,
|
||||
"timeout_seconds": settings.sandbox_timeout_s,
|
||||
},
|
||||
)
|
||||
@@ -838,6 +841,58 @@ def build_tools(ctx: ToolContext) -> list[Any]:
|
||||
out["last_seen_version"] = live_card.get("version")
|
||||
return json.dumps(out)
|
||||
|
||||
@tool
|
||||
async def cp_deploy_source_repo(name: str) -> str:
|
||||
"""Deploy the current managed source repo for ``name``.
|
||||
|
||||
Use this when source changes already live in the platform-managed
|
||||
Gitea repo. Do not use it for normal MinIO builder workspaces; for
|
||||
those, run ``test_agent_in_sandbox`` and then ``cp_deploy_tarball``.
|
||||
|
||||
Returns JSON from the control plane, including ``deploy_id`` and a
|
||||
serialized ``deployment`` when one is queued.
|
||||
"""
|
||||
try:
|
||||
_validate_name(name)
|
||||
except ValueError as exc:
|
||||
return json.dumps({"error": str(exc)})
|
||||
if not ctx.cp_jwt:
|
||||
return json.dumps({
|
||||
"error": "no CP JWT forwarded — agent declaration missing wants_cp_jwt=True",
|
||||
})
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=60.0) as c:
|
||||
r = await c.post(
|
||||
f"{settings.cp_url}/v1/agents/{name}/source/deploy",
|
||||
headers={"authorization": f"bearer {ctx.cp_jwt}"},
|
||||
)
|
||||
except httpx.HTTPError as exc:
|
||||
return json.dumps({"error": f"cp unreachable: {exc}"})
|
||||
if r.status_code >= 400:
|
||||
return json.dumps({"error": f"cp {r.status_code}", "detail": r.text[:1000]})
|
||||
payload = r.json()
|
||||
body = payload if isinstance(payload, dict) else {}
|
||||
deployment = body.get("deployment") if isinstance(body, dict) else None
|
||||
url = None
|
||||
if isinstance(deployment, dict):
|
||||
url = deployment.get("agent_url")
|
||||
out = {
|
||||
"ok": True,
|
||||
"name": body.get("agent_name") or name,
|
||||
"status": body.get("status") or (deployment or {}).get("status"),
|
||||
"url": url or _canonical_agent_url(name),
|
||||
"head_sha": body.get("source_sha"),
|
||||
"deployment_id": body.get("deploy_id"),
|
||||
"deployment": deployment or {},
|
||||
"already_deployed": bool(body.get("already_deployed")),
|
||||
"skipped": bool(body.get("skipped")),
|
||||
}
|
||||
if body.get("summary"):
|
||||
out["summary"] = body.get("summary")
|
||||
if body.get("reason"):
|
||||
out["reason"] = body.get("reason")
|
||||
return json.dumps(out)
|
||||
|
||||
@tool
|
||||
async def cp_compose_meta_agent(
|
||||
name: str,
|
||||
@@ -1121,7 +1176,7 @@ def build_tools(ctx: ToolContext) -> list[Any]:
|
||||
return [
|
||||
init_agent_template, list_agent_files, write_agent_file, read_agent_file,
|
||||
write_agent_skill, test_agent_in_sandbox, cp_deploy_tarball,
|
||||
cp_compose_meta_agent, cp_refresh_agent,
|
||||
cp_deploy_source_repo, cp_compose_meta_agent, cp_refresh_agent,
|
||||
sync_agent_workspace_from_repo,
|
||||
list_a2a_pack, read_a2a_pack,
|
||||
]
|
||||
@@ -1457,6 +1512,8 @@ def _compile_agent_dsl_json(bundle: bytes) -> str:
|
||||
entrypoint = str(cfg.get("entrypoint") or "").strip()
|
||||
if not entrypoint:
|
||||
raise ValueError("a2a.yaml entrypoint is required")
|
||||
entrypoint_module = entrypoint.split(":", 1)[0].strip()
|
||||
old_entrypoint_module = sys.modules.get(entrypoint_module)
|
||||
old_dont_write_bytecode = os.environ.get("PYTHONDONTWRITEBYTECODE")
|
||||
old_sys_dont_write_bytecode = sys.dont_write_bytecode
|
||||
os.environ["PYTHONDONTWRITEBYTECODE"] = "1"
|
||||
@@ -1483,6 +1540,10 @@ def _compile_agent_dsl_json(bundle: bytes) -> str:
|
||||
else:
|
||||
os.environ["PYTHONDONTWRITEBYTECODE"] = old_dont_write_bytecode
|
||||
sys.dont_write_bytecode = old_sys_dont_write_bytecode
|
||||
if old_entrypoint_module is None:
|
||||
sys.modules.pop(entrypoint_module, None)
|
||||
else:
|
||||
sys.modules[entrypoint_module] = old_entrypoint_module
|
||||
return dsl.model_dump_json()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user