--- title: ChemGraph Loop emoji: ๐Ÿงช colorFrom: green colorTo: yellow sdk: docker app_port: 7860 pinned: false license: apache-2.0 short_description: Real agentic chemistry workflow โ€” resolve, simulate, verify --- # ChemGraph Loop A guarded, **natural-language API around the real ChemGraph agent** โ€” Argonne Leadership Computing Facility's agentic computational-chemistry framework (LangGraph + ASE), running the workflow-correctness hardening by **Lu Zhang**. Backs the live demo at **sciencesloop.com/agent** (frontend = `lu-zhang-site/src/components/ChemGraphDemo.astro`). - **GitHub (source):** `github.com/rockyzl/chemgraph-loop` (private) - **Deploy target:** HF Space `rockyaaos/chemgraph-loop` (Docker, free CPU-basic) - **Upstream ChemGraph:** https://github.com/argonne-lcf/ChemGraph (Apache-2.0) ## How it works (request lifecycle) 1. **LLM intent router** (`llm_parse_query`, PRIMARY) โ€” one `gpt-4o-mini` JSON call reads the plain-language question and returns `{molecule, task, calculator}`, resolving the molecule by ANY name/synonym/formula ("dihydrogen monoxide"/"H2O"/"NH3"/"CO2"/"EtOH"/"benzol" โ†’ canonical). It refuses to match derivatives to a parent (dimethoxybenzene โ‰  benzene) and emits `nearest`/`note` for out-of-scope molecules. `keyword_fallback` (token match, no regex) runs ONLY if the model call fails. This is intentionally agentic, not a rule engine. 2. **Route by physics cost:** - `energy` / `dipole` = single-point (~12โ€“25 s) โ†’ run the **real ChemGraph agent LIVE** on a canonical, guard-matched query built from the intent. - `ir` / `thermo` = finite-difference Hessian (too slow for free CPU) โ†’ served from **precomputed real agent runs** in `precomputed/` (`cached:true`, shown as "precomputed real run"). 3. **Extract** (`cg_extract.extract`) โ†’ unified rich payload: molecule/formula/ smiles, `structure.atoms` (parsed from molecule.xyz, drives the 3D viewer), `steps[]` (tool calls + folded detail), task-specific `result` (energy / dipole vector+magnitude / ir.modes / thermo H,S,G), `verified`. 4. **Clarification node** โ€” out-of-scope molecule or an unavailable heavy task returns `{clarify:true, message, suggestions:[{label,query}]}` (HTTP 200), NOT an error. The frontend renders it as a conversational bubble + chips. ## Endpoints ``` GET / โ†’ health: molecules, tasks, live_tasks, ir_molecules, thermo_molecules POST /run { "query": "IR spectrum of water" } # natural-language (primary) POST /run { "molecule": "water", "calculator": "emt" } # legacy, energy only ``` `/run` returns one of: a rich result payload ยท a `clarify` payload ยท an error (`429` rate limit ยท `504` timeout ยท `500` agent error). ## Coverage & reliability (IMPORTANT) - **energy / dipole:** LIVE for all 10 allow-listed molecules (water, methane, ammonia, methanol, ethanol, carbon dioxide, benzene, acetic acid, formaldehyde, hydrogen peroxide). - **thermochemistry:** precomputed for **all 10** (thermo uses plain `Vibrations`; works for large molecules). - **IR / vibrations:** precomputed for **โ‰ค4-atom molecules only** โ€” water, ammonia, carbon dioxide, formaldehyde, hydrogen peroxide. The ASE `Infrared` intensity step returns **empty modes for โ‰ฅ5-atom molecules** (methane, methanol, ethanol, acetic acid, benzene all fail โ€” confirmed). Do NOT add โ‰ฅ5-atom IR; the clarification node covers them. - Guard-matched queries only (single-point / dipole / ir / thermo). "geometry optimization" phrasing makes the agent loop โ€” never expose it. - Display-layer IR filter: keep modes with `cm1 โ‰ฅ 100` & `intensity > 1e-3` (drops spurious near-zero / translation-rotation modes). ## Files | File | Role | |---|---| | `app.py` | FastAPI: intent router, routing, clarification node, guards (CORS, rate limit, timeout) | | `cg_extract.py` | shared payload extractor (structure/steps/results) โ€” used by app + precompute | | `precompute.py` | offline heavy-task generator: `python precompute.py ` | | `precomputed/__.json` | bundled real agent runs for ir/thermo | | `Dockerfile` | CPU torch โ†’ `pip install .[calculators]` โ†’ copies wrappers LAST (fast layer-cached rebuilds) | | `src/` | vendored copy of Lu's hardened ChemGraph fork | ## Deploy / operate The HF Space builds from its own git; push files with `huggingface_hub` (`~/.local` env at `/tmp/hfenv/bin/python` on Lu's box) โ€” `upload_file` / `upload_folder` / `delete_file` each trigger a rebuild (~2โ€“4 min, layer-cached since wrappers copy late). `OPENAI_API_KEY` is a Space **secret**. ```python from huggingface_hub import HfApi HfApi().upload_file(path_or_fileobj="app.py", path_in_repo="app.py", repo_id="rockyaaos/chemgraph-loop", repo_type="space", commit_message="...") ``` **Add a spectrum/thermo molecule:** run `precompute.py `, validate the IR modes are non-empty & physical (`cm1โ‰ฅ100`), `upload_file` the JSON, let the Space rebuild (its `_avail(task)` picks it up automatically). Only โ‰ค4-atom molecules get valid IR. CORS allows `sciencesloop.com`, `*.vercel.app`, and `localhost:4321`.