"""agent.py — A Hermes-powered agent that can call tools.

A normal model only talks. An *agent* can decide to use tools — like a
calculator, a clock, or a search function — and then keep talking with
the result in hand. Hermes 3 is specifically trained for this.

We give Hermes three small tools below. Watch the verbose output to see
the model decide which tool to call and why.

Before running:
    ollama pull hermes3:8b

Then:
    python agent.py

Try asking:
    - "What is 23 times 47, then divided by 9?"
    - "How many days until Songkran 2027?" (April 13)
    - "Read my notes and summarise what I wrote about Chiang Mai."
"""
import asyncio
from datetime import date
from pathlib import Path

from llama_index.core.agent.workflow import ReActAgent
from llama_index.core.tools import FunctionTool
from llama_index.llms.ollama import Ollama


# ── Tools the agent can choose to call ──────────────────────────────


def multiply(a: float, b: float) -> float:
    """Multiply two numbers and return the product."""
    return a * b


def divide(a: float, b: float) -> float:
    """Divide a by b and return the quotient. Returns 0 if b is zero."""
    return a / b if b else 0


def days_until(iso_date: str) -> str:
    """How many days between today and a YYYY-MM-DD date."""
    target = date.fromisoformat(iso_date)
    delta = (target - date.today()).days
    if delta == 0:
        return "today"
    if delta > 0:
        return f"{delta} day(s) from now"
    return f"{-delta} day(s) ago"


def read_notes() -> str:
    """Read every .md file in the ./notes folder and return the joined text."""
    folder = Path("notes")
    if not folder.exists():
        return "No notes folder found."
    chunks = []
    for f in sorted(folder.glob("*.md")):
        chunks.append(f"--- {f.name} ---\n{f.read_text(encoding='utf-8')}")
    return "\n\n".join(chunks) if chunks else "Notes folder is empty."


TOOLS = [
    FunctionTool.from_defaults(multiply),
    FunctionTool.from_defaults(divide),
    FunctionTool.from_defaults(days_until),
    FunctionTool.from_defaults(read_notes),
]


# ── Wire it up ──────────────────────────────────────────────────────


async def main() -> None:
    llm = Ollama(model="hermes3:8b", request_timeout=300, context_window=8192)
    agent = ReActAgent(tools=TOOLS, llm=llm, verbose=True)

    print("Hermes agent ready. Empty line to quit.\n")
    while True:
        try:
            q = input("you > ").strip()
        except (EOFError, KeyboardInterrupt):
            print()
            return
        if not q:
            return
        response = await agent.run(user_msg=q)
        print(f"\nagent > {response}\n")


if __name__ == "__main__":
    asyncio.run(main())
