Spaces:
Paused
Paused
File size: 15,144 Bytes
287f3d3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | """Helpers: valid sample outputs per agent + an agent-detecting handler."""
from __future__ import annotations
import json
import re
AGENT_MARKERS: list[tuple[str, str]] = [
("discovery", "Discovery Agent"),
("requirements", "Requirements Engineer agent"),
("architecture", "Architecture agent"),
("database", "Database Design agent"),
("api", "API Design agent"),
("devops", "DevOps Engineer agent"),
("reviewer", "Review Agent"),
("summarizer", "Artifact Summarizer agent"),
]
def detect_agent(system_prompt: str) -> str:
for name, marker in AGENT_MARKERS:
if marker in system_prompt:
return name
return "unknown"
def discovery_output(status: str = "ready") -> dict:
return {
"status": status,
"confidence": 0.94 if status == "ready" else 0.6,
"summary": "A platform where users order food from local restaurants and track delivery.",
"known_information": {
"problem": "Ordering food takes too long",
"target_users": ["Customers", "Restaurants"],
"user_roles": ["Customer", "Restaurant Owner", "Admin"],
"business_goals": ["Increase orders", "Fast delivery"],
"core_features": [
"Restaurant discovery",
"Order placement",
"Online payment",
"Delivery tracking",
],
"payment_requirement": "Online payment",
"notification_requirement": "Order status notifications",
},
"missing_information": [] if status == "ready" else [
{"field": "user_roles", "importance": "critical", "reason": "Required to define authorization"}
],
"questions": [] if status == "ready" else [
{"id": "q1", "question": "Who are the main users of the platform?", "reason": "Defines roles and permissions."}
],
}
def requirements_output() -> dict:
return {
"functional_requirements": [
"FR1: Users can browse restaurants and menus.",
"FR2: Users can place orders and pay online.",
"FR3: Users can track delivery status.",
],
"non_functional_requirements": [
"NFR1: The system must respond within 500ms for core operations.",
"NFR2: Payment data must be encrypted in transit and at rest.",
],
"user_stories": [
"As a customer, I want to order food online, so that I save time.",
"As a restaurant owner, I want to receive orders, so that I can fulfill them.",
],
"acceptance_criteria": [
"AC1: A customer can complete an order end-to-end.",
"AC2: Payment failures return a clear error.",
],
"constraints": ["Must run on commodity cloud infrastructure."],
"assumptions": ["Payment provider is Stripe."],
}
def architecture_output() -> dict:
return {
"system_components": [
{"name": "Web Frontend", "type": "frontend", "description": "React SPA", "technology": "React"},
{"name": "API Backend", "type": "backend", "description": "REST API", "technology": "FastAPI (Python)"},
{"name": "Database", "type": "database", "description": "Primary datastore", "technology": "PostgreSQL"},
{"name": "Payments", "type": "external", "description": "Payment processing", "technology": "Stripe"},
],
"communication": ["Frontend calls the API over HTTPS", "API persists to PostgreSQL"],
"authentication": "JWT bearer tokens",
"security": ["TLS everywhere", "Rate limiting on auth endpoints"],
"scalability": ["Horizontal scaling of the API behind a load balancer"],
"technology_stack": {
"frontend": "React",
"backend": "FastAPI (Python)",
"database": "PostgreSQL",
"payments": "Stripe",
},
"deployment_architecture": "Containerized services on a single cloud VM, scaled out as needed.",
"mermaid_diagram": "flowchart TD\n FE[Web Frontend] --> API[API Backend]\n API --> DB[(PostgreSQL)]\n API --> PS[Stripe]",
}
def database_output() -> dict:
return {
"database_technology": "PostgreSQL",
"entities": [
{
"name": "users",
"description": "Platform users",
"fields": [
{"name": "id", "type": "uuid", "primary_key": True, "nullable": False, "unique": False, "indexed": False, "foreign_key": None},
{"name": "email", "type": "varchar", "primary_key": False, "nullable": False, "unique": True, "indexed": True, "foreign_key": None},
{"name": "role", "type": "varchar", "primary_key": False, "nullable": False, "unique": False, "indexed": False, "foreign_key": None},
],
},
{
"name": "orders",
"description": "Food orders",
"fields": [
{"name": "id", "type": "uuid", "primary_key": True, "nullable": False, "unique": False, "indexed": False, "foreign_key": None},
{"name": "user_id", "type": "uuid", "primary_key": False, "nullable": False, "unique": False, "indexed": True, "foreign_key": "users.id"},
{"name": "status", "type": "varchar", "primary_key": False, "nullable": False, "unique": False, "indexed": False, "foreign_key": None},
],
},
],
"relationships": ["orders.user_id references users.id"],
"indexes": ["idx_orders_user_id ON orders(user_id)"],
"constraints": ["orders.status CHECK in ('pending','paid','delivered')"],
"sql_schema": "CREATE TABLE users (id uuid PRIMARY KEY, email varchar NOT NULL UNIQUE, role varchar NOT NULL);\nCREATE TABLE orders (id uuid PRIMARY KEY, user_id uuid NOT NULL REFERENCES users(id), status varchar NOT NULL);",
"erd_mermaid": "erDiagram\n users ||--o{ orders : places",
}
def api_output() -> dict:
return {
"endpoints": [
{
"method": "GET",
"path": "/api/restaurants",
"summary": "List restaurants",
"auth": "none",
"pagination": True,
"filters": ["cuisine"],
"request_schema": None,
"response_schema": {"type": "object", "properties": {"items": {"type": "array"}}},
},
{
"method": "POST",
"path": "/api/orders",
"summary": "Place an order",
"auth": "jwt",
"pagination": False,
"filters": [],
"request_schema": {"type": "object", "properties": {"restaurant_id": {"type": "string"}}},
"response_schema": {"type": "object", "properties": {"id": {"type": "string"}}},
},
{
"method": "GET",
"path": "/api/orders/{id}",
"summary": "Get an order",
"auth": "jwt",
"pagination": False,
"filters": [],
"request_schema": None,
"response_schema": {"type": "object", "properties": {"status": {"type": "string"}}},
},
],
"authentication": "JWT bearer tokens",
"authorization": "Customers access their own orders; owners access their restaurant data",
"error_handling": ["Standard error envelope with code/message/request_id", "404 for missing resources"],
"pagination": "cursor-based",
"filtering": "query parameters",
"openapi_spec": {"openapi": "3.0.0", "info": {"title": "Food Delivery API", "version": "1.0.0"}, "paths": {}},
}
def devops_output() -> dict:
return {
"dockerfile": "FROM python:3.11-slim\nWORKDIR /app\nCOPY requirements.txt .\nRUN pip install -r requirements.txt\nCOPY . .\nCMD [\"uvicorn\", \"app.main:app\", \"--host\", \"0.0.0.0\"]",
"docker_compose": "services:\n api:\n build: .\n ports: ['8000:8000']\n db:\n image: postgres:16",
"ci_cd_pipeline": "Lint, test, build image, push to registry, deploy to VM",
"github_actions": "name: CI\non: [push]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4",
"environment_variables": {"DATABASE_URL": "postgres://user:pass@db:5432/app", "STRIPE_SECRET_KEY": "${STRIPE_SECRET_KEY}"},
"deployment_strategy": "Docker Compose on a single VM with rolling container restarts",
"health_checks": ["/health endpoint on API", "pg_isready for database"],
"logging": ["Structured JSON logs to stdout"],
"monitoring": ["Prometheus metrics on /metrics"],
"secrets_management": "Secrets injected via environment variables from the CI/CD provider secret store",
}
def review_output(status: str = "approved") -> dict:
if status == "approved":
return {"status": "approved", "score": 0.96, "issues": [], "artifacts_to_regenerate": []}
return {
"status": "needs_revision",
"score": 0.7,
"issues": [
{
"artifact": "database",
"severity": "blocking",
"problem": "Database technology conflicts with architecture.",
"expected": "PostgreSQL",
"actual": "MongoDB",
"fix": "Switch database_technology to PostgreSQL.",
"source_artifact": "architecture",
"source_decision": "Database component technology: PostgreSQL",
"conflicting_artifact": "database",
"conflicting_decision": "database_technology: MongoDB",
}
],
"artifacts_to_regenerate": ["database"],
}
def review_output_targets(targets: list[str]) -> dict:
"""A needs_revision review flagging ``targets`` as blocking."""
issues = [
{
"artifact": target,
"severity": "blocking",
"problem": f"{target} artifact is inconsistent.",
"expected": "expected value",
"actual": "actual value",
"fix": "fix it",
"source_artifact": "database",
"source_decision": "decision",
"conflicting_artifact": target,
"conflicting_decision": "decision",
}
for target in targets
]
return {
"status": "needs_revision",
"score": 0.6,
"issues": issues,
"artifacts_to_regenerate": targets,
}
def summary_text(name: str) -> str:
"""A plausible compact summary for each artifact (plain text, as the real
summarizer produces)."""
return {
"requirements": (
"Requirements summary: FR1-FR3 and NFR1-NFR2 captured; "
"key constraints preserved."
),
"architecture": (
"Architecture summary: Web Frontend (React), API Backend (FastAPI), "
"Database (PostgreSQL), Stripe; JWT auth."
),
"database": (
"Database summary: PostgreSQL; entities users (id, email, role), "
"orders (id, user_id, status); foreign key orders.user_id -> users.id."
),
"api": (
"API summary: GET /api/restaurants, POST /api/orders, "
"GET /api/orders/{id}; JWT auth; cursor pagination."
),
"devops": (
"DevOps summary: Docker Compose on a VM; health checks /health and "
"pg_isready; Prometheus metrics; env-var secrets."
),
}.get(name, f"Summary of {name}: key facts preserved.")
def build_handler(discovery_status: str = "ready", review_status: str = "approved", review_sequence: list[str] | None = None):
"""Return a handler that answers every agent with valid output.
``review_sequence`` overrides review answers call-by-call when provided.
A revision call (user prompt contains ``REVISION TASK``) returns a *changed*
artifact so the orchestrator's hash-based convergence check sees a real
change (as the real LLM would produce).
"""
review_index = 0
reviews = list(review_sequence) if review_sequence else None
def handler(system_prompt: str, user_prompt: str) -> str:
nonlocal review_index
agent = detect_agent(system_prompt)
if agent == "discovery":
return json.dumps(discovery_output(discovery_status))
if agent == "requirements":
base = requirements_output()
return json.dumps(revised_output(agent, base) if "REVISION TASK" in user_prompt else base)
if agent == "architecture":
base = architecture_output()
return json.dumps(revised_output(agent, base) if "REVISION TASK" in user_prompt else base)
if agent == "database":
base = database_output()
return json.dumps(revised_output(agent, base) if "REVISION TASK" in user_prompt else base)
if agent == "api":
base = api_output()
return json.dumps(revised_output(agent, base) if "REVISION TASK" in user_prompt else base)
if agent == "devops":
base = devops_output()
return json.dumps(revised_output(agent, base) if "REVISION TASK" in user_prompt else base)
if agent == "reviewer":
if reviews is not None:
answer = reviews[min(review_index, len(reviews) - 1)]
review_index += 1
return json.dumps(review_output(answer))
return json.dumps(review_output(review_status))
if agent == "summarizer":
match = re.search(r"Artifact: (\w+)", user_prompt)
name = match.group(1) if match else "unknown"
return summary_text(name)
raise AssertionError(f"Unknown agent marker in: {system_prompt[:80]}")
return handler
def revised_output(agent: str, base: dict) -> dict:
"""Return a *changed* artifact for a revision run, so the orchestrator's
hash-based convergence check sees the artifact actually changed."""
out = dict(base)
if agent == "database":
out["constraints"] = list(base.get("constraints") or []) + ["review_revision_applied"]
elif agent == "api":
out["authentication"] = (base.get("authentication") or "") + " (revised)"
elif agent == "devops":
out["deployment_strategy"] = (base.get("deployment_strategy") or "") + " (revised)"
elif agent == "architecture":
out["deployment_architecture"] = (base.get("deployment_architecture") or "") + " (revised)"
elif agent == "requirements":
out["constraints"] = list(base.get("constraints") or []) + ["review_revision_applied"]
return out |