# Get started

This guide walks through the main features of the AIR SDK.

## Create a client

```python
import os
import air

client = air.AIR(
    api_key=os.environ["AIR_API_KEY"],
    base_url=os.environ.get("AIR_BASE_URL", "http://localhost:8000"),
)
```

If `AIR_API_KEY` and `AIR_BASE_URL` are set as environment variables you can
omit both arguments:

```python
client = air.AIR()
```

Optionally set `local_dir` to control where project files are synced locally
(defaults to `~/ai-scientist` or the `AIR_LOCAL_DIR` environment variable):

```python
client = air.AIR(
    api_key=os.environ["AIR_API_KEY"],
    base_url=os.environ.get("AIR_BASE_URL", "http://localhost:8000"),
    local_dir="~/my-research",
)
```

## Health check

```python
print(client.health())
```

## Keyword extraction

Extract keywords from text using different taxonomies:

- **UNESCO** — broad academic classification, works for any discipline
- **AAS** — American Astronomical Society, for astronomy & astrophysics
- **AAAI** — for artificial intelligence and computer science

```python
# UNESCO keywords (any discipline)
keywords = client.keywords(
    "Adenosine triphosphate (ATP) is the primary energy currency of all "
    "living cells, providing energy for metabolic processes.",
    n=5,
    kw_type="unesco",
)
print(keywords)

# AAS keywords (astronomy)
keywords = client.keywords(
    "We study cosmic microwave background anisotropies and dark energy models.",
    n=5,
    kw_type="aas",
)
print(keywords)
```

## OCR

Download a paper from arXiv and extract its full text with OCR.
The result includes both plain text and markdown (preserving structure,
headings, equations, and tables):

```python
# Download from arXiv
arxiv_result = client.arxiv("https://arxiv.org/abs/1706.03762")
pdf_path = arxiv_result["downloaded_files"][0]

# Run OCR
ocr_result = client.ocr(pdf_path)
full_text = ocr_result.get("full_text", "")
full_markdown = ocr_result.get("full_markdown", "")

# Save markdown locally
with open("paper.md", "w") as f:
    f.write(full_markdown)
```

## Text enhancement

Enhance a task description with context from arXiv papers. When you
reference arXiv papers in your text, the enhance tool fetches and
summarises them, producing enriched text that gives AI agents much
better context to work with:

```python
enhanced = client.enhance("""
We want to implement the variational quantum eigensolver (VQE)
described in https://arxiv.org/abs/1304.3061 to estimate the
ground state energy of small molecules.
""")
print(enhanced)
```

## One-shot execution

`one_shot` runs a free-form task where the backend drives an AI agent loop
and all generated code executes **locally** on your machine inside an isolated
virtual environment.

### Engineer (code generation)

```python
result = client.one_shot(
    task="Generate synthetic patient data and plot a ROC curve.",
    agent="engineer",
    # model="gemini-3.1-flash-lite-preview",  # optional model override
    max_rounds=25,
    max_attempts=3,
    work_dir="./output_engineer",
)

print("Files:", [f.path for f in result.files_created])
```

### Researcher (writing, no code)

```python
result = client.one_shot(
    task="Write a comparative analysis of utilitarianism, deontological "
         "ethics, and virtue ethics applied to AI in academic publishing.",
    agent="researcher",
    max_rounds=25,
    work_dir="./output_researcher",
)
```

### With VLM image review

When `enable_vlm_review=True`, a vision-language model reviews generated
plots and provides feedback. The engineer iterates until the plot is
publication-quality:

```python
result = client.one_shot(
    task="Plot a 2D phase space diagram of the Lorenz attractor "
         "with a colorbar showing time evolution.",
    agent="engineer",
    enable_vlm_review=True,
    max_vlm_review_attempts=3,
    work_dir="./output_vlm",
)
```

### With self-hosted OSS model

Use a self-hosted open-source model for all agents:

```python
result = client.one_shot(
    task="Write a summary of how large language models are trained.",
    agent="researcher",
    model="gpt-oss-120b",
    defaultModel="gpt-oss-120b",
    defaultFormatterModel="gpt-oss-120b",
    work_dir="./output_oss",
)
```

### Available models

Examples of models that can be passed via the `model` parameter:

| Model | Notes |
|-------|-------|
| `gemini-3.1-flash-lite-preview` | Fast, cheapest — good default |
| `gemini-3.1-pro-preview` | Stronger reasoning |
| `gpt-5-nano` | Fast, good quality |
| `gpt-5.2` | Strongest OpenAI model |
| `claude-sonnet-4-6` | Strong all-round |
| `gpt-oss-120b` | Self-hosted, free (requires vLLM server) |

If `model` is not set, the server default is used.

## Deep research

`deep_research` runs a multi-step research task with a planner, reviewer,
engineer, and researcher agent. Code executes **locally**:

```python
result = client.deep_research(
    task="""
    We have an RCT dataset with 400 patients followed over 24 months.
    1. Generate synthetic survival data. Fit a Cox model, plot Kaplan-Meier curves.
    2. Write a data guide interpreting the results.
    """,
    max_plan_steps=2,
    n_plan_reviews=1,
    plan_instructions="1. engineer, 2. researcher.",
    engineer_model="gemini-3.1-flash-lite-preview",
    researcher_model="gpt-oss-120b",
    max_rounds=100,
    max_attempts=3,
    # adaptive_planning=True,   # enable adaptive re-planning after each step
    work_dir="./output_deep_research",
)

print("Files:", [f.path for f in result.files_created])
```

## Research projects

Projects let you run the full AIR research pipeline: **idea &rarr; literature
&rarr; methods &rarr; results &rarr; paper &rarr; review**.

### Create a project

The data description grounds the AI in your research context. Include your
research question, available data, experimental setup, hardware/software
resources, and any constraints:

```python
project = client.create_project(
    "quantum-error-correction",
    data_description="""
    We are interested in exploring new approaches to quantum error correction
    for near-term noisy intermediate-scale quantum (NISQ) devices.

    Context and resources:
    - Access to IBM Quantum Experience (ibmq_manila, 5-qubit device)
    - Qiskit SDK for circuit design and simulation
    - Local workstation with 128GB RAM for classical simulation of up to 20 qubits
    - Noise models extracted from real device calibration data
    """,
)
```

### Idea generation

```python
idea = project.idea(
    default_model="gpt-4.1-2025-04-14",   # LLM for idea generation
    critic_model="gemini-3.1-pro-preview", # LLM for the idea critic
    idea_iterations=3,                      # maker <-> critic rounds
)
print(idea)
```

### Literature search

```python
literature = project.literature(
    timeout=900,         # literature search can be slow
    max_iterations=10,   # max Semantic Scholar queries
)
print(literature)
```

### Methods development

```python
methods = project.methods(
    default_model="gpt-4.1-2025-04-14",          # LLM for methods writer
    critic_model="gemini-3.1-flash-lite-preview", # LLM for reviewers
)
print(methods)
```

### Results (local code execution)

The `results()` step runs code **locally** on your machine and automatically
uploads generated plots to the server so `paper()` can embed them:

```python
results = project.results(
    max_steps=2,                                     # plan steps
    max_attempts=5,                                  # retries per step
    n_plan_reviews=1,                                # plan review rounds
    engineer_model="gemini-3.1-flash-lite-preview",  # LLM for engineer
    researcher_model="gemini-3.1-flash-lite-preview",# LLM for researcher
    work_dir="./output_results",                     # local execution dir
)
```

### Paper writing

Paper writing requires a capable model for structured output:

```python
paper = project.paper(
    journal="AAS",                          # target journal formatting
    add_citations=True,                     # include bibliography
    default_model="gemini-2.5-flash",       # needs a capable model
    timeout=1000,
)
```

### Review

```python
review = project.review()
```

### Manage projects

```python
# List all projects
print(client.list_projects())

# Re-open an existing project
project = client.get_project("quantum-error-correction")

# Delete a project
client.delete_project("quantum-error-correction")
```

### Sync files locally

When `auto_pull=True` (the default), key files are automatically
downloaded to `local_dir` after each pipeline step.

```python
# Download all project files
paths = project.pull_files()

# Download only key files for a specific iteration
paths = project.pull_files(key_only=True, iteration=0)

# Upload a local file to the project
project.push_files("local/data.csv")
```

### Access project files

```python
# List all files
for f in project.list_files():
    print(f["relative_path"], f["size"])

# Read a specific file
idea_text = project.get_file("Iteration0/input_files/idea.md")

# Write a file
project.write_file("notes.md", "# My notes\n...")
```
