chore: pydantic-settings config, logging, CI workflow
Config (src/config.py): - pydantic-settings Settings class: OLLAMA_URL, OLLAMA_MODEL, DEBUG - Reads from .env (gitignored) with sane defaults - settings singleton imported by health.py and agent.py Removes two hardcodes: - health.py: OLLAMA_URL="http://localhost:11434" → settings.ollama_url - agent.py: Ollama(id="llama3.2") → settings.ollama_model app.py: - logging.basicConfig at INFO — requests/errors now visible in terminal - docs_url/redoc_url gated on settings.debug (off by default) pyproject.toml: - pydantic-settings>=2.0.0 added to main dependencies - hatch wheel config updated to include src/config.py .env.example: documents all three env vars with inline comments .gitignore: add !.env.example negation so the template gets committed .github/workflows/tests.yml: runs pytest --cov on every push/PR (ubuntu-latest, Python 3.11, pip cache) All 27 tests pass. https://claude.ai/code/session_01M4L3R98N5fgXFZRvV8X9b6
This commit is contained in:
13
.env.example
Normal file
13
.env.example
Normal file
@@ -0,0 +1,13 @@
|
||||
# Timmy Time — Mission Control
|
||||
# Copy this file to .env and uncomment lines you want to override.
|
||||
# .env is gitignored and never committed.
|
||||
|
||||
# Ollama host (default: http://localhost:11434)
|
||||
# Override if Ollama is running on another machine or port.
|
||||
# OLLAMA_URL=http://localhost:11434
|
||||
|
||||
# LLM model to use via Ollama (default: llama3.2)
|
||||
# OLLAMA_MODEL=llama3.2
|
||||
|
||||
# Enable FastAPI interactive docs at /docs and /redoc (default: false)
|
||||
# DEBUG=true
|
||||
25
.github/workflows/tests.yml
vendored
Normal file
25
.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
pull_request:
|
||||
branches: ["**"]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
cache: "pip"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install -e ".[dev]"
|
||||
|
||||
- name: Run tests
|
||||
run: pytest --cov=src --cov-report=term-missing
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -13,9 +13,10 @@ dist/
|
||||
venv/
|
||||
env/
|
||||
|
||||
# Secrets / local config
|
||||
# Secrets / local config — commit only .env.example (the template)
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# SQLite memory — never commit agent memory
|
||||
*.db
|
||||
|
||||
@@ -19,6 +19,7 @@ dependencies = [
|
||||
"aiofiles>=24.0.0",
|
||||
"typer>=0.12.0",
|
||||
"rich>=13.0.0",
|
||||
"pydantic-settings>=2.0.0",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
@@ -32,7 +33,8 @@ dev = [
|
||||
timmy = "timmy.cli:main"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/timmy", "src/dashboard"]
|
||||
sources = {"src" = ""}
|
||||
include = ["src/timmy", "src/dashboard", "src/config.py"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
|
||||
21
src/config.py
Normal file
21
src/config.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
# Ollama host — override with OLLAMA_URL env var or .env file
|
||||
ollama_url: str = "http://localhost:11434"
|
||||
|
||||
# LLM model passed to Agno/Ollama — override with OLLAMA_MODEL
|
||||
ollama_model: str = "llama3.2"
|
||||
|
||||
# Set DEBUG=true to enable /docs and /redoc (disabled by default)
|
||||
debug: bool = False
|
||||
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=".env",
|
||||
env_file_encoding="utf-8",
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
|
||||
settings = Settings()
|
||||
@@ -1,3 +1,4 @@
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
@@ -5,13 +6,27 @@ from fastapi.responses import HTMLResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
|
||||
from config import settings
|
||||
from dashboard.routes.agents import router as agents_router
|
||||
from dashboard.routes.health import router as health_router
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s %(levelname)-8s %(name)s — %(message)s",
|
||||
datefmt="%H:%M:%S",
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
BASE_DIR = Path(__file__).parent
|
||||
PROJECT_ROOT = BASE_DIR.parent.parent
|
||||
|
||||
app = FastAPI(title="Timmy Time — Mission Control", version="1.0.0")
|
||||
app = FastAPI(
|
||||
title="Timmy Time — Mission Control",
|
||||
version="1.0.0",
|
||||
# Docs disabled unless DEBUG=true in env / .env
|
||||
docs_url="/docs" if settings.debug else None,
|
||||
redoc_url="/redoc" if settings.debug else None,
|
||||
)
|
||||
|
||||
templates = Jinja2Templates(directory=str(BASE_DIR / "templates"))
|
||||
app.mount("/static", StaticFiles(directory=str(PROJECT_ROOT / "static")), name="static")
|
||||
|
||||
@@ -4,17 +4,17 @@ from fastapi.responses import HTMLResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from pathlib import Path
|
||||
|
||||
from config import settings
|
||||
|
||||
router = APIRouter(tags=["health"])
|
||||
templates = Jinja2Templates(directory=str(Path(__file__).parent.parent / "templates"))
|
||||
|
||||
OLLAMA_URL = "http://localhost:11434"
|
||||
|
||||
|
||||
async def check_ollama() -> bool:
|
||||
"""Ping Ollama to verify it's running."""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=2.0) as client:
|
||||
r = await client.get(OLLAMA_URL)
|
||||
r = await client.get(settings.ollama_url)
|
||||
return r.status_code == 200
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@@ -3,13 +3,14 @@ from agno.models.ollama import Ollama
|
||||
from agno.db.sqlite import SqliteDb
|
||||
|
||||
from timmy.prompts import TIMMY_SYSTEM_PROMPT
|
||||
from config import settings
|
||||
|
||||
|
||||
def create_timmy(db_file: str = "timmy.db") -> Agent:
|
||||
"""Instantiate Timmy with Agno + Ollama + SQLite memory."""
|
||||
return Agent(
|
||||
name="Timmy",
|
||||
model=Ollama(id="llama3.2"),
|
||||
model=Ollama(id=settings.ollama_model),
|
||||
db=SqliteDb(db_file=db_file),
|
||||
description=TIMMY_SYSTEM_PROMPT,
|
||||
add_history_to_context=True,
|
||||
|
||||
Reference in New Issue
Block a user