<!-- Source of truth: DOCS.md · canonical page: https://delfhos.com/docs/tutorials · v0.8.7 -->
<!-- This is the raw-markdown rendition for LLMs and tools. -->

# Tutorials

*Tutorials are learning-oriented. They are designed to guide you through the experience of building something real with Delfhos for the first time. Follow them in order.*

---

## Tutorial 1 — Your First Agent

This tutorial gets you from zero to a running AI agent in five minutes.

### Step 1: Install Delfhos

```bash
pip install delfhos
```

### Step 2: Set your API key

Delfhos works with Google Gemini, OpenAI, and Anthropic. Create a `.env` file in your project root:

```bash
# .env
GOOGLE_API_KEY=your_gemini_key_here
```

Or export it in your shell:

```bash
export GOOGLE_API_KEY="your_gemini_key_here"
```

### Step 3: Write and run your first agent

Create a file called `hello_agent.py`:

```python
from delfhos import Agent, WebSearch

# Create an agent with web search capability
agent = Agent(
    tools=[WebSearch(llm="gemini-3.5-flash")],
    llm="gemini-3.5-flash",
)

# Run a task
result = agent.run("What are the top 3 AI trends right now?")

print(result.text)
print(f"Cost: ${result.cost_usd:.4f}")
print(f"Duration: {result.duration_ms}ms")

agent.stop()
```

Run it:

```bash
python hello_agent.py
```

You should see a structured answer, cost, and duration printed to the terminal.

### What just happened?

When you called `agent.run(...)`, Delfhos:

1. Sent your task to the LLM for code generation
2. Generated Python code that calls the WebSearch tool
3. Executed that code in an isolated sandbox environment
4. Returned the result to the LLM to compose a final answer
5. Returned a `Response` object with the answer, cost, and timing

---

## Tutorial 2 — Connecting to Gmail

This tutorial walks you through connecting an agent to a real Gmail account so it can read and send emails.

### Step 1: Get OAuth credentials

1. Go to the [Google Cloud Console](https://console.cloud.google.com/)
2. Create a project (or select an existing one)
3. Enable the **Gmail API**
4. Go to **Credentials → Create Credentials → OAuth client ID**
5. Choose **Desktop app**, download the JSON file
6. Save it as `client_secrets.json` in your project folder

### Step 2: Build the agent

```python
from delfhos import Agent, Gmail

# First run will open a browser for OAuth consent
gmail = Gmail(
    oauth_credentials="client_secrets.json",
    allow=["read", "send"],     # Restrict to only these actions
    confirm=["send"],           # Require human approval before sending
)

agent = Agent(
    tools=[gmail],
    llm="gemini-3.5-flash",
)

result = agent.run("Summarize the 5 most recent unread emails in my inbox.")
print(result.text)

agent.stop()
```

On the first run, your browser opens and asks you to authorize Gmail access. After you click **Allow**, Delfhos saves the token at `~/.config/oauth_gmail.json` and re-uses it automatically on all future runs.

### Step 3: Try sending an email (with approval)

```python
result = agent.run("Send a short greeting email to alice@example.com")
```

Because you set `confirm=["send"]`, the terminal pauses and shows:

```
╔══════════════════════════════════╗
║     ACTION APPROVAL REQUIRED     ║
╠══════════════════════════════════╣
║  Tool: gmail.send                ║
║  To:   alice@example.com         ║
╚══════════════════════════════════╝

  > Approve
    Reject
```

Select **Approve** to let the agent proceed.

---

## Tutorial 3 — Custom Tools

This tutorial teaches you how to expose your own Python functions as agent tools using the `@tool` decorator.

### Step 1: Define a simple tool

```python
from delfhos import Agent, tool

@tool
def calculate_discount(price: float, discount_pct: float) -> float:
    """Calculate the final price after applying a percentage discount."""
    return price * (1 - discount_pct / 100)
```

The decorator automatically extracts the function name, docstring, and type hints to create a schema the LLM can understand.

### Step 2: Register and run

```python
agent = Agent(
    tools=[calculate_discount],
    llm="gemini-3.5-flash",
)

result = agent.run("What is the final price of a $250 item with a 15% discount?")
print(result.text)
# → "The final price after a 15% discount is $212.50."
agent.stop()
```

### Step 3: Add error handling

Use `ToolException` to send error messages back to the LLM instead of crashing:

```python
from delfhos import Agent, tool, ToolException

@tool(confirm=False)
def get_user_tier(user_id: str) -> str:
    """Look up a user's subscription tier: free, pro, or enterprise."""
    users = {"u001": "pro", "u002": "enterprise"}
    if user_id not in users:
        raise ToolException(f"User '{user_id}' not found in the system.")
    return users[user_id]
```

When `ToolException` is raised, Delfhos catches it and feeds the message back to the LLM, which can then try a different approach or ask the user for clarification.

### Step 4: Async tools

Tools can be `async`. Delfhos handles both sync and async transparently:

```python
import aiohttp

@tool
async def fetch_price(symbol: str) -> float:
    """Fetch the current stock price for a ticker symbol."""
    async with aiohttp.ClientSession() as session:
        async with session.get(f"https://api.example.com/price/{symbol}") as r:
            data = await r.json()
            return data["price"]
```

---

## Tutorial 4 — Chat Mode and Memory

This tutorial shows how to build a persistent, context-aware chat agent.

### Step 1: Enable session memory with Chat

```python
from delfhos import Agent, Chat, Gmail

agent = Agent(
    tools=[Gmail(oauth_credentials="client_secrets.json")],
    llm="gemini-3.5-flash",
    chat=Chat(
        keep=10,                          # Keep the last 10 messages
        summarize=True,                   # Auto-compress older messages
        summarizer_llm="gemini-3.5-flash",
    ),
)

# The agent remembers context across multiple run() calls
agent.run("Who emailed me this morning?")
agent.run("Reply to the first one saying I'll follow up tomorrow")

agent.stop()
```

### Step 2: Start an interactive terminal session

```python
agent.run_chat()   # Launches an interactive REPL in your terminal
```

Inside the session you can type naturally. Special commands:

| Command  | Action                                  |
|----------|-----------------------------------------|
| `/help`  | Show available commands                 |
| `/exit`  | Exit the chat session                   |
| `/stop`  | Stop the agent (restarts on next input) |
| `/clear` | Clear the terminal screen               |

### Step 3: Add persistent long-term memory

```python
from delfhos import Agent, Chat, Memory, Gmail

# Persistent memory survives across program restarts
memory = Memory(namespace="alice_support_agent")

# Pre-load facts once
memory.save("""
Primary contact: Alice Chen, alice@acme.com
Company: Acme Corp, Enterprise tier
Account manager: Bob (bob@ourco.com)
Preferred contact: email, not Slack
""")

agent = Agent(
    tools=[Gmail(oauth_credentials="client_secrets.json")],
    llm="gemini-3.5-flash",
    chat=Chat(summarizer_llm="gemini-3.5-flash"),
    memory=memory,
)

agent.run("Draft a check-in email to our primary contact")
# The agent uses memory to know Alice's email without being told again
```

---

---
