Spaces:
Sleeping
Sleeping
README: full dev/ops doc
Browse files
README.md
CHANGED
|
@@ -12,26 +12,97 @@ short_description: Real agentic chemistry workflow β resolve, simulate, verify
|
|
| 12 |
|
| 13 |
# ChemGraph Loop
|
| 14 |
|
| 15 |
-
A
|
| 16 |
-
Computing Facility's agentic computational-chemistry framework
|
| 17 |
-
running the workflow-correctness hardening by **Lu Zhang**.
|
| 18 |
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
engine for a single-point energy, and **audits its own result** against a
|
| 22 |
-
deterministic workflow guard. The API returns the structured agentic trace so a
|
| 23 |
-
site can show the loop running.
|
| 24 |
|
| 25 |
-
|
|
|
|
|
|
|
| 26 |
|
| 27 |
-
##
|
| 28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
```
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
```
|
| 33 |
|
| 34 |
-
|
| 35 |
-
|
|
|
|
|
|
|
| 36 |
|
| 37 |
-
|
|
|
|
| 12 |
|
| 13 |
# ChemGraph Loop
|
| 14 |
|
| 15 |
+
A guarded, **natural-language API around the real ChemGraph agent** β Argonne
|
| 16 |
+
Leadership Computing Facility's agentic computational-chemistry framework
|
| 17 |
+
(LangGraph + ASE), running the workflow-correctness hardening by **Lu Zhang**.
|
| 18 |
|
| 19 |
+
Backs the live demo at **sciencesloop.com/agent** (frontend =
|
| 20 |
+
`lu-zhang-site/src/components/ChemGraphDemo.astro`).
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
+
- **GitHub (source):** `github.com/rockyzl/chemgraph-loop` (private)
|
| 23 |
+
- **Deploy target:** HF Space `rockyaaos/chemgraph-loop` (Docker, free CPU-basic)
|
| 24 |
+
- **Upstream ChemGraph:** https://github.com/argonne-lcf/ChemGraph (Apache-2.0)
|
| 25 |
|
| 26 |
+
## How it works (request lifecycle)
|
| 27 |
|
| 28 |
+
1. **LLM intent router** (`llm_parse_query`, PRIMARY) β one `gpt-4o-mini` JSON
|
| 29 |
+
call reads the plain-language question and returns `{molecule, task,
|
| 30 |
+
calculator}`, resolving the molecule by ANY name/synonym/formula
|
| 31 |
+
("dihydrogen monoxide"/"H2O"/"NH3"/"CO2"/"EtOH"/"benzol" β canonical). It
|
| 32 |
+
refuses to match derivatives to a parent (dimethoxybenzene β benzene) and
|
| 33 |
+
emits `nearest`/`note` for out-of-scope molecules. `keyword_fallback`
|
| 34 |
+
(token match, no regex) runs ONLY if the model call fails. This is
|
| 35 |
+
intentionally agentic, not a rule engine.
|
| 36 |
+
2. **Route by physics cost:**
|
| 37 |
+
- `energy` / `dipole` = single-point (~12β25 s) β run the **real ChemGraph
|
| 38 |
+
agent LIVE** on a canonical, guard-matched query built from the intent.
|
| 39 |
+
- `ir` / `thermo` = finite-difference Hessian (too slow for free CPU) β
|
| 40 |
+
served from **precomputed real agent runs** in `precomputed/`
|
| 41 |
+
(`cached:true`, shown as "precomputed real run").
|
| 42 |
+
3. **Extract** (`cg_extract.extract`) β unified rich payload: molecule/formula/
|
| 43 |
+
smiles, `structure.atoms` (parsed from molecule.xyz, drives the 3D viewer),
|
| 44 |
+
`steps[]` (tool calls + folded detail), task-specific `result`
|
| 45 |
+
(energy / dipole vector+magnitude / ir.modes / thermo H,S,G), `verified`.
|
| 46 |
+
4. **Clarification node** β out-of-scope molecule or an unavailable heavy task
|
| 47 |
+
returns `{clarify:true, message, suggestions:[{label,query}]}` (HTTP 200),
|
| 48 |
+
NOT an error. The frontend renders it as a conversational bubble + chips.
|
| 49 |
+
|
| 50 |
+
## Endpoints
|
| 51 |
+
|
| 52 |
+
```
|
| 53 |
+
GET / β health: molecules, tasks, live_tasks, ir_molecules, thermo_molecules
|
| 54 |
+
POST /run { "query": "IR spectrum of water" } # natural-language (primary)
|
| 55 |
+
POST /run { "molecule": "water", "calculator": "emt" } # legacy, energy only
|
| 56 |
```
|
| 57 |
+
|
| 58 |
+
`/run` returns one of: a rich result payload Β· a `clarify` payload Β· an error
|
| 59 |
+
(`429` rate limit Β· `504` timeout Β· `500` agent error).
|
| 60 |
+
|
| 61 |
+
## Coverage & reliability (IMPORTANT)
|
| 62 |
+
|
| 63 |
+
- **energy / dipole:** LIVE for all 10 allow-listed molecules (water, methane,
|
| 64 |
+
ammonia, methanol, ethanol, carbon dioxide, benzene, acetic acid,
|
| 65 |
+
formaldehyde, hydrogen peroxide).
|
| 66 |
+
- **thermochemistry:** precomputed for **all 10** (thermo uses plain
|
| 67 |
+
`Vibrations`; works for large molecules).
|
| 68 |
+
- **IR / vibrations:** precomputed for **β€4-atom molecules only** β water,
|
| 69 |
+
ammonia, carbon dioxide, formaldehyde, hydrogen peroxide. The ASE `Infrared`
|
| 70 |
+
intensity step returns **empty modes for β₯5-atom molecules** (methane,
|
| 71 |
+
methanol, ethanol, acetic acid, benzene all fail β confirmed). Do NOT add
|
| 72 |
+
β₯5-atom IR; the clarification node covers them.
|
| 73 |
+
- Guard-matched queries only (single-point / dipole / ir / thermo). "geometry
|
| 74 |
+
optimization" phrasing makes the agent loop β never expose it.
|
| 75 |
+
- Display-layer IR filter: keep modes with `cm1 β₯ 100` & `intensity > 1e-3`
|
| 76 |
+
(drops spurious near-zero / translation-rotation modes).
|
| 77 |
+
|
| 78 |
+
## Files
|
| 79 |
+
|
| 80 |
+
| File | Role |
|
| 81 |
+
|---|---|
|
| 82 |
+
| `app.py` | FastAPI: intent router, routing, clarification node, guards (CORS, rate limit, timeout) |
|
| 83 |
+
| `cg_extract.py` | shared payload extractor (structure/steps/results) β used by app + precompute |
|
| 84 |
+
| `precompute.py` | offline heavy-task generator: `python precompute.py <molecule...>` |
|
| 85 |
+
| `precomputed/<slug>__<task>.json` | bundled real agent runs for ir/thermo |
|
| 86 |
+
| `Dockerfile` | CPU torch β `pip install .[calculators]` β copies wrappers LAST (fast layer-cached rebuilds) |
|
| 87 |
+
| `src/` | vendored copy of Lu's hardened ChemGraph fork |
|
| 88 |
+
|
| 89 |
+
## Deploy / operate
|
| 90 |
+
|
| 91 |
+
The HF Space builds from its own git; push files with `huggingface_hub`
|
| 92 |
+
(`~/.local` env at `/tmp/hfenv/bin/python` on Lu's box) β `upload_file` /
|
| 93 |
+
`upload_folder` / `delete_file` each trigger a rebuild (~2β4 min, layer-cached
|
| 94 |
+
since wrappers copy late). `OPENAI_API_KEY` is a Space **secret**.
|
| 95 |
+
|
| 96 |
+
```python
|
| 97 |
+
from huggingface_hub import HfApi
|
| 98 |
+
HfApi().upload_file(path_or_fileobj="app.py", path_in_repo="app.py",
|
| 99 |
+
repo_id="rockyaaos/chemgraph-loop", repo_type="space",
|
| 100 |
+
commit_message="...")
|
| 101 |
```
|
| 102 |
|
| 103 |
+
**Add a spectrum/thermo molecule:** run `precompute.py <name>`, validate the IR
|
| 104 |
+
modes are non-empty & physical (`cm1β₯100`), `upload_file` the JSON, let the Space
|
| 105 |
+
rebuild (its `_avail(task)` picks it up automatically). Only β€4-atom molecules
|
| 106 |
+
get valid IR.
|
| 107 |
|
| 108 |
+
CORS allows `sciencesloop.com`, `*.vercel.app`, and `localhost:4321`.
|