"""Swarm I/O tests (agent_swarm#40 + result delivery): receive user prompts + return result. Exercises the real HTTP endpoints via FastAPI TestClient (hermetic: REDIS_FAKE, planner offline, no connected agents, launch backend = none): * POST /api/swarms/{id}/input — injects a `source="user_append"` task; the raw instruction is delivered to the agent (task description) but **redacted from the event stream** (task.created carries only a category message); rejects a stopped run. * GET /api/swarms/{id}/result — returns {summary, deliverable, artifacts, termination_reason}. Run from agent_swarm_v6 (install deps first): pip install -r orchestrator/requirements.txt REDIS_FAKE=1 python scripts/test-swarm-io.py """ import json import logging import os import sys from pathlib import Path os.environ["REDIS_FAKE"] = "1" sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from fastapi.testclient import TestClient from orchestrator import main as orch orch.planner.client = None # force planner offline (no model calls) logging.getLogger("orchestrator.swarm_runtime").setLevel(logging.ERROR) failures = [] SECRET_PROMPT = "SUPER-SECRET-USER-FOLLOWUP-PROMPT-9173-do-the-thing" def check(name, cond): print(("PASS" if cond else "FAIL"), "-", name) if not cond: failures.append(name) def create_run(client): body = {"mode": "swarm", "requirement": {"objective": "build add(a,b)"}, "callback": {"url": "http://127.0.0.1:9/cb", "subscribed_events": []}, "metadata": {"manager_deployment_id": "io-1"}} r = client.post("/api/swarms", json=body) return r.json()["data"]["deployment_id"] def main(): with TestClient(orch.app) as client: dep = create_run(client) check("run created", bool(dep)) # --- receive user prompt (append) --- ri = client.post(f"/api/swarms/{dep}/input", json={"instruction": SECRET_PROMPT}) check("input accepted (200/success)", ri.status_code == 200 and ri.json().get("success")) idata = ri.json().get("data", {}) check("input created a user_append task", bool(idata.get("task_id"))) # the appended task carries the instruction (agent-facing) ... tasks = client.get(f"/api/swarms/{dep}/tasks").json()["data"]["tasks"] appended = [t for t in tasks if t.get("source") == "user_append"] check("appended task present with source=user_append", len(appended) == 1) check("appended task description = the instruction (agent-facing)", appended and appended[0].get("description") == SECRET_PROMPT) # ... but the instruction is NOT echoed into the event stream (redaction). events = client.get(f"/api/swarms/{dep}/logs").json()["data"]["events"] blob = json.dumps(events, ensure_ascii=False) check("instruction NOT in any event payload (redacted)", SECRET_PROMPT not in blob) tc = [e for e in events if e["event_type"] == "task.created" and (e.get("payload") or {}).get("source") == "user_append"] check("a redacted task.created(user_append) event was emitted", len(tc) == 1) check("that event carries a category message, not the prompt", tc and "message" in tc[0]["payload"] and SECRET_PROMPT not in json.dumps(tc[0]["payload"], ensure_ascii=False)) # --- result endpoint --- res = client.get(f"/api/swarms/{dep}/result") check("result endpoint 200/success", res.status_code == 200 and res.json().get("success")) rdata = res.json().get("data", {}) check("result has summary/deliverable/artifacts keys", {"summary", "deliverable", "artifacts", "status"}.issubset(rdata.keys())) check("result deliverable is a dict", isinstance(rdata.get("deliverable"), dict)) # --- stopped run rejects append --- client.post(f"/api/swarms/{dep}/stop", json={"reason": "test stop"}) rstop = client.post(f"/api/swarms/{dep}/input", json={"instruction": "more"}) body = rstop.json() check("append to stopped run rejected (RUN_STOPPED)", body.get("success") is False and (body.get("error") or {}).get("code") == "RUN_STOPPED") print() if failures: print(f"{len(failures)} swarm-io check(s) FAILED: {failures}") sys.exit(1) print("all swarm-io checks passed") if __name__ == "__main__": main()