Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Deploy Documentation
on:
push:
branches: [main]
paths:
- 'docs/**'
- 'mkdocs.yml'
workflow_dispatch:

permissions:
contents: write

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: 3.x

- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV

- uses: actions/cache@v4
with:
key: mkdocs-material-${{ env.cache_id }}
path: ~/.cache
restore-keys: |
mkdocs-material-

- run: pip install mkdocs-material pymdown-extensions

- run: mkdocs gh-deploy --force
2 changes: 1 addition & 1 deletion agapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Version number."""

__version__ = "2026.2.2"
__version__ = "2026.3.2"

import os

Expand Down
567 changes: 511 additions & 56 deletions agapi/agents/schema.py

Large diffs are not rendered by default.

File renamed without changes.
27 changes: 23 additions & 4 deletions agapi/tests/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from agapi.agents.client import AGAPIClient
from agapi.agents.functions import *
import pytest

import time
# pytest.skip("Temporarily disabled", allow_module_level=True)

# ---------------------------------------------------------------------
Expand Down Expand Up @@ -71,28 +71,33 @@ def client():
# =====================================================================

def test_query_by_formula(client):
time.sleep(4)
r = query_by_formula("Si", client)
assert "error" not in r


def test_query_by_jid(client):
time.sleep(4)
r = query_by_jid("JVASP-1002", client)
assert "error" not in r
assert isinstance(r.get("POSCAR"), str)


def test_query_by_elements(client):
time.sleep(4)
r = query_by_elements("Si", client)
assert "error" not in r


def test_query_by_property(client):
time.sleep(4)
r = query_by_property("bandgap", 0.1, 3.0,
elements="Si", api_client=client)
assert "error" not in r


def test_find_extreme(client):
time.sleep(4)
r = find_extreme("bulk modulus", True,
elements="Si", api_client=client)
assert "error" not in r
Expand All @@ -103,16 +108,19 @@ def test_find_extreme(client):
# =====================================================================

def test_alignn_predict(client):
time.sleep(4)
r = alignn_predict(jid="JVASP-1002", api_client=client)
assert r.get("status") == "success"


def test_alignn_ff_relax(client):
r = alignn_ff_relax(SI_PRIM, api_client=client)
assert r.get("status") == "success"
#def test_alignn_ff_relax(client):
# time.sleep(4)
# r = alignn_ff_relax(SI_PRIM, api_client=client)
# assert r.get("status") == "success"


def test_alignn_ff_single_point(client):
time.sleep(4)
r = alignn_ff_single_point(SI_PRIM, api_client=client)
assert "energy_eV" in r

Expand All @@ -133,6 +141,7 @@ def test_alignn_ff_md(client):
# =====================================================================

def test_slakonet_bandstructure(client):
time.sleep(4)
r = slakonet_bandstructure(SI_PRIM, api_client=client)
assert r.get("status") == "success"

Expand All @@ -142,6 +151,7 @@ def test_slakonet_bandstructure(client):
# =====================================================================

def test_generate_interface(client):
time.sleep(4)
r = generate_interface(SI_PRIM, GAAS_PRIM, api_client=client)
assert r.get("status") == "success"

Expand All @@ -151,21 +161,25 @@ def test_generate_interface(client):
# =====================================================================

def test_make_supercell():
time.sleep(4)
r = make_supercell(SI_PRIM, [2, 2, 1])
assert r["supercell_atoms"] > r["original_atoms"]


def test_substitute_atom():
time.sleep(4)
r = substitute_atom(GAAS_PRIM, "Ga", "Al", 1)
assert "Al" in r["new_formula"]


def test_create_vacancy():
time.sleep(4)
r = create_vacancy(GAAS_PRIM, "Ga", 1)
assert r["new_atoms"] == r["original_atoms"] - 1


def test_generate_xrd_pattern():
time.sleep(4)
r = generate_xrd_pattern(SI_PRIM)
assert r["formula"] == "Si"

Expand All @@ -175,6 +189,7 @@ def test_generate_xrd_pattern():
# =====================================================================

def test_diffractgpt_predict(client):
time.sleep(4)
r = diffractgpt_predict("Si", "28.4(1.0),47.3(0.49)", client)
assert isinstance(r, dict)

Expand All @@ -184,6 +199,7 @@ def test_diffractgpt_predict(client):
# =====================================================================

def test_protein_fold_validation(client):
time.sleep(4)
r = protein_fold("MKTAY", api_client=client)
assert "error" in r

Expand All @@ -201,11 +217,13 @@ def test_openfold_predict(client):
# =====================================================================

def test_pxrd_match(client):
time.sleep(4)
r = pxrd_match("Si", SI_XRD, api_client=client)
assert isinstance(r, dict)


def test_xrd_analyze(client):
time.sleep(4)
r = xrd_analyze("Si", SI_XRD, api_client=client)
assert isinstance(r, dict)

Expand All @@ -226,6 +244,7 @@ def test_query_mp(client):

"""
def test_query_oqmd(client):
time.sleep(4)
r = query_oqmd("Si", limit=2, api_client=client)
assert isinstance(r, dict)

Expand Down
118 changes: 118 additions & 0 deletions docs/api/agents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
title: AGAPI Agents
---

# AGAPI Agents

The AGAPI Agent uses natural language to orchestrate multi-step materials science workflows.

## Setup

```python
import os
from agapi.agents import AGAPIAgent

agent = AGAPIAgent(api_key=os.environ.get("AGAPI_KEY"))
```

## Natural Language Queries

```python
# Simple property lookup
agent.query_sync("What is the bandgap of Silicon?")

# Database search
agent.query_sync("Show me all MgB2 polymorphs")
agent.query_sync("Find materials with bulk modulus > 200 GPa")

# Comparisons
agent.query_sync("Compare bandgaps across BN, AlN, GaN, InN")

# Predictions
agent.query_sync("Predict properties of JVASP-1002 with ALIGNN")

# Characterization
agent.query_sync("Identify the phase from this XRD pattern for Silicon")
agent.query_sync("Analyze this STEM image of a GaN thin film")

# Literature
agent.query_sync("Find recent papers on perovskite solar cells on arXiv")
```

## Multi-Step Workflows

The agent chains multiple tools automatically:

```python
agent.query_sync("""
1. Find all GaN materials in JARVIS-DFT
2. Get POSCAR for the most stable one
3. Make a 2x1x1 supercell
4. Substitute one Ga with Al
5. Generate powder XRD pattern
6. Optimize structure with ALIGNN-FF
7. Predict properties with ALIGNN
""", max_context_messages=20, verbose=True)
```

```python
agent.query_sync("""
Create a GaN/AlN heterostructure interface:
1. Find GaN (most stable)
2. Find AlN (most stable)
3. Generate (001)/(001) interface
4. Show POSCAR
""", max_context_messages=20, verbose=True)
```

## Supported LLM Backends

Set `model` when initializing the agent:

```python
agent = AGAPIAgent(
api_key=os.environ.get("AGAPI_KEY"),
model="openai/gpt-oss-20b"
)
```

| Provider | Model |
|----------|-------|
| OpenAI | `openai/gpt-oss-20b` |
| OpenAI | `openai/gpt-oss-120b` |
| Meta | `meta/llama-4-maverick-17b-128e-instruct` |
| Meta | `meta/llama-3.2-90b-vision-instruct` |
| Meta | `meta/llama-3.2-1b-instruct` |
| Google | `google/gemini-2.5-flash` |
| Google | `google/gemma-3-27b-it` |
| DeepSeek | `deepseek-ai/deepseek-v3.1` |
| Moonshot | `moonshotai/kimi-k2-instruct-0905` |
| Qwen | `qwen/qwen3-next-80b-a3b-instruct` |

## Architecture

AGAPI implements a modular architecture separating the **reasoning layer** (LLM brain) from the **execution layer** (scientific tools and databases) through a unified REST API interface.

```
┌──────────────────┐
│ Natural Language │ ← user prompt
└────────┬─────────┘
┌──────────────────┐
│ LLM Backend │ ← GPT-OSS / Llama / Gemini / DeepSeek
│ (Reasoning) │
└────────┬─────────┘
┌──────────────────┐
│ AGAPI Functions │ ← query_by_formula, alignn_predict, ...
│ (Execution) │
└────────┬─────────┘
┌──────────────────┐
│ AtomGPT.org API │ ← JARVIS-DFT, ALIGNN, ALIGNN-FF, ...
│ (Data + Models) │
└──────────────────┘
```

!!! info "AGAPI Name"
**AGAPI (ἀγάπη)** is a Greek word meaning *unconditional love*.
6 changes: 6 additions & 0 deletions docs/api/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: Index
---

# API Reference
REST API for all 50+ AtomGPT apps.
8 changes: 8 additions & 0 deletions docs/api/optimade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: Optimade
---

# OPTIMADE API
OPTIMADE-standard access.

Coming soon.
Loading