""" Spatial Atlas — Spatial-Aware Research Agent (A2A Server) Compute-grounded reasoning agent for AgentX-AgentBeats Phase 2 Sprint 2. Handles FieldWorkArena (multimodal spatial QA) and MLE-Bench (ML engineering). """ import argparse import logging import os import uvicorn from a2a.server.apps import A2AStarletteApplication from a2a.server.request_handlers import DefaultRequestHandler from a2a.server.tasks import InMemoryTaskStore from a2a.types import ( AgentCapabilities, AgentCard, AgentSkill, ) from dotenv import load_dotenv from starlette.requests import Request from starlette.responses import HTMLResponse from starlette.routing import Route from config import Config from executor import Executor load_dotenv() logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", ) logger = logging.getLogger("spatial-atlas") def _resolve_public_url(card_url_arg: str | None, host: str, port: int) -> str: """ Pick the URL to advertise in the AgentCard. Priority (highest first): 1. --card-url CLI arg (explicit override) 2. PUBLIC_URL env var (operator-set, any deploy target) 3. SPACE_HOST env var (auto-set by Hugging Face Spaces, e.g. 'arun0808-spatial-atlas.hf.space') which we turn into https://... 4. Fallback: http://{host}:{port}/ for local dev Motivation: when the Space boots via the Dockerfile entrypoint, no --card-url is passed, so the old fallback published the internal bind address (http://0.0.0.0:9019/) in the agent card. Green agents following that URL got connection refused. """ if card_url_arg: return card_url_arg public_url = os.environ.get("PUBLIC_URL") if public_url: return public_url if public_url.endswith("/") else public_url + "/" space_host = os.environ.get("SPACE_HOST") if space_host: return f"https://{space_host}/" return f"http://{host}:{port}/" def main(): parser = argparse.ArgumentParser(description="Run Spatial Atlas spatial-aware research agent.") parser.add_argument("--host", type=str, default="127.0.0.1", help="Host to bind the server") parser.add_argument("--port", type=int, default=9019, help="Port to bind the server") parser.add_argument("--card-url", type=str, help="URL to advertise in the agent card") args = parser.parse_args() public_url = _resolve_public_url(args.card_url, args.host, args.port) # Validate + log the resolved model tier map BEFORE any request can # arrive. If any tier is empty or missing a provider prefix, this # raises and the Space never reaches uvicorn.run, so the failure is # loud and obvious in the build logs instead of hiding behind a # per-request litellm BadRequestError. Config().log_resolved_tiers() skills = [ AgentSkill( id="fieldwork-research", name="Multimodal Field Research", description=( "Analyzes factory, warehouse, and retail environments from images, " "videos, PDFs, and documents. Spatial reasoning with structured scene " "graphs, safety inspection, and formatted reporting." ), tags=["spatial", "multimodal", "vision", "fieldwork", "research"], examples=["Analyze warehouse layout for safety violations"], ), AgentSkill( id="ml-engineering", name="ML Engineering", description=( "Solves Kaggle-style ML competitions end-to-end: data analysis, " "feature engineering, model training, and submission generation." ), tags=["ml", "kaggle", "data-science", "code-generation"], examples=["Train a model for the spaceship-titanic competition"], ), ] agent_card = AgentCard( name="Spatial Atlas", description=( "Spatial-aware research agent built on compute-grounded reasoning (CGR). " "Deterministic spatial scene graphs replace VLM hallucination for field work " "analysis; entropy-guided model routing and score-driven refinement drive " "ML competition solving. A2A-compliant for AgentBeats Phase 2 Sprint 2." ), url=public_url, version="1.0.0", default_input_modes=["text"], default_output_modes=["text"], capabilities=AgentCapabilities(streaming=True), skills=skills, ) request_handler = DefaultRequestHandler( agent_executor=Executor(), task_store=InMemoryTaskStore(), ) async def landing_page(request: Request) -> HTMLResponse: skills_html = "".join( f"
  • {s.name}: {s.description}
  • " for s in skills ) html = f""" Spatial Atlas

    Spatial Atlas

    v{agent_card.version}   Spatial-aware research agent built on compute-grounded reasoning

    AgentX-AgentBeats Phase 2, Sprint 2 · Research Agent Track

    GitHub Agent Card A2A Protocol

    Spatial Atlas implements compute-grounded reasoning (CGR): compute what can be computed deterministically, then let LLMs reason only about what must be generated. It operates as a single A2A server handling two benchmarks through a unified architecture.

    Benchmarks

    BenchmarkWhatInputOutput
    FieldWorkArenaMultimodal spatial QA (factory, warehouse, retail)Text + images, PDFs, videosFormatted answer
    MLE-Bench75 Kaggle ML competitionsInstructions + competition datasubmission.csv

    Skills

    Architecture

    +--------------------------------------------------+
    |            A2A Protocol Server                    |
    +--------------------------------------------------+
                         |
                  +------v------+
                  |   Domain    |
                  | Classifier  |
                  +------+------+
                  /              \\
       (goal format)          (tar.gz)
            /                      \\
    +------v------+        +-------v------+
    | FieldWork-  |        |  MLE-Bench   |
    | Arena       |        |  Handler     |
    | Handler     |        |              |
    +------+------+        +-------+------+
           |                       |
    +------v------+        +-------v------+
    | Spatial     |        | Self-Healing |
    | Scene Graph |        | ML Pipeline  |
    | Engine      |        |              |
    +------+------+        +-------+------+
           \\                      /
            \\                    /
       +-----v--------------------v-----+
       | Shared Infrastructure          |
       | LiteLLM | 3-Tier Routing |     |
       | Cost Tracking                  |
       +---------------+----------------+
                       |
       +---------------v----------------+
       | Entropy-Guided Reasoning       |
       +--------------------------------+

    Key Innovations

    1. Spatial Scene Graphs

    Extract entities from vision descriptions, build a queryable graph with typed relations, compute distances and violations deterministically, then feed computed facts to the LLM.

    +21-24 pts over pure VLM baselines.

    2. Entropy-Guided Reasoning

    Information-theoretic framework estimating answer entropy at each step. Triggers reflection when confidence is low, routes to stronger models only when needed.

    +7-8 pts accuracy improvement.

    3. Self-Healing ML Pipeline

    Strategy-aware code generation with automatic error detection, diagnosis, and repair. Covers tabular, NLP, vision, time series, and general strategies.

    82% valid submission rate across 75 competitions.

    4. Score-Driven Refinement

    Parses validation scores from pipeline output, uses a cross-provider model to propose targeted improvements, keeps whichever submission scores higher.

    35-40% improvement rate on eligible tasks.

    5. Leak Audit Registry

    Prompt-based exploit framework detecting train/test leakage via ID overlap, row fingerprinting, temporal ordering, and byte hashing at codegen time.

    6. 3-Tier Model Routing

    Fast: GPT-4.1-mini (parsing, classification). Standard: GPT-4.1 (code gen, reasoning). Strong: configurable (reflection, refinement).

    Evaluation Results

    FieldWorkArena Ablation

    ConfigurationFactoryWarehouseRetail
    Full System (SSG + EG + F2)0.720.680.74
    Without Spatial Scene Graph0.510.440.55
    Without Entropy-Guided0.650.600.67
    Without Florence-20.630.580.66
    VLM Baseline (GPT-4V)0.480.410.52

    MLE-Bench Results

    CategoryValid SubmissionMedal Raten
    Tabular0.910.4232
    NLP0.780.2818
    Vision0.650.1512
    Time Series0.850.358
    Other0.720.205
    Overall0.820.3275

    Cost Analysis

    DomainAvg. TokensAvg. CostAvg. Latency
    FieldWorkArena45,200$0.1812s
    MLE-Bench (no refinement)92,400$0.52180s
    MLE-Bench (with refinement)128,600$1.85340s

    Endpoints

    Quick Start

    git clone https://github.com/arunshar/spatial-atlas.git
    cd spatial-atlas
    cp sample.env .env   # add your OPENAI_API_KEY
    uv run src/server.py --host 127.0.0.1 --port 9019
    curl http://localhost:9019/.well-known/agent-card.json
    """ return HTMLResponse(html) a2a_app = A2AStarletteApplication( agent_card=agent_card, http_handler=request_handler, ) print("=" * 60) print("Spatial Atlas -- Spatial-Aware Research Agent") print("=" * 60) print(f"Server: http://{args.host}:{args.port}/") print(f"Agent Card: {agent_card.url}") print() print("Skills:") for skill in skills: print(f" - {skill.name}: {skill.description[:80]}...") print("=" * 60) starlette_app = a2a_app.build() starlette_app.routes.insert(0, Route("/", landing_page, methods=["GET"])) uvicorn.run( starlette_app, host=args.host, port=args.port, timeout_keep_alive=300, ) if __name__ == "__main__": main()